168395f370d11ac3d114a7f959e1e48740d12a75
[blender.git] / intern / smoke / intern / smoke_API.cpp
1 /**
2  * $Id$
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) 2009 by Daniel Genrich
21  * All rights reserved.
22  *
23  * Contributor(s): Daniel Genrich
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 #include "FLUID_3D.h"
29 #include "WTURBULENCE.h"
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <math.h>
34
35 // y in smoke is z in blender
36 extern "C" FLUID_3D *smoke_init(int *res, float *p0)
37 {
38         // smoke lib uses y as top-bottom/vertical axis where blender uses z
39         FLUID_3D *fluid = new FLUID_3D(res, p0);
40
41         // printf("xres: %d, yres: %d, zres: %d\n", res[0], res[1], res[2]);
42
43         return fluid;
44 }
45
46 extern "C" WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype)
47 {
48         // initialize wavelet turbulence
49         if(amplify)
50                 return new WTURBULENCE(res[0],res[1],res[2], amplify, noisetype);
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         // // const int index = x + y * smd->res[0] + z * smd->res[0]*smd->res[1];
70         return x + y * max_x + z * max_x*max_y;
71 }
72
73 extern "C" size_t smoke_get_index2d(int x, int max_x, int y /*, int max_y, int z, int max_z */)
74 {
75         return x + y * max_x;
76 }
77
78 extern "C" void smoke_step(FLUID_3D *fluid, size_t framenr, float fps)
79 {
80         /* stability values copied from wturbulence.cpp */
81         const int maxSubSteps = 25;
82         const float maxVel = 0.5f; /* TODO: maybe 0.5 is still too high, please confirm! -dg */
83
84         float dt = DT_DEFAULT;
85         float maxVelMag = 0.0f;
86         int totalSubsteps;
87         int substep = 0;
88         float dtSubdiv;
89
90         /* get max velocity and lower the dt value if it is too high */
91         size_t size= fluid->_xRes * fluid->_yRes * fluid->_zRes;
92
93         for(size_t i = 0; i < size; i++)
94         {
95                 float vtemp = (fluid->_xVelocity[i]*fluid->_xVelocity[i]+fluid->_yVelocity[i]*fluid->_yVelocity[i]+fluid->_zVelocity[i]*fluid->_zVelocity[i]);
96                 if(vtemp > maxVelMag)
97                         maxVelMag = vtemp;
98         }
99
100         /* adapt timestep for different framerates, dt = 0.1 is at 25fps */
101         dt *= (25.0f / fps);
102
103         maxVelMag = sqrt(maxVelMag) * dt * (*(fluid->_dtFactor));
104         totalSubsteps = (int)((maxVelMag / maxVel) + 1.0f); /* always round up */
105         totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps;
106         totalSubsteps = (totalSubsteps > maxSubSteps) ? maxSubSteps : totalSubsteps;
107         dtSubdiv = (float)dt / (float)totalSubsteps;
108
109         // printf("totalSubsteps: %d, maxVelMag: %f, dt: %f\n", totalSubsteps, maxVelMag, dt);
110
111         for(substep = 0; substep < totalSubsteps; substep++)
112                 fluid->step(dtSubdiv);
113 }
114
115 extern "C" void smoke_turbulence_step(WTURBULENCE *wt, FLUID_3D *fluid)
116 {
117         wt->stepTurbulenceFull(fluid->_dt/fluid->_dx, fluid->_xVelocity, fluid->_yVelocity, fluid->_zVelocity, fluid->_obstacles); 
118 }
119
120 extern "C" void smoke_initBlenderRNA(FLUID_3D *fluid, float *alpha, float *beta, float *dt_factor, float *vorticity, int *border_colli)
121 {
122         fluid->initBlenderRNA(alpha, beta, dt_factor, vorticity, border_colli);
123 }
124
125 extern "C" void smoke_dissolve(FLUID_3D *fluid, int speed, int log)
126 {
127         float *density = fluid->_density;
128         //float *densityOld = fluid->_densityOld;
129         float *heat = fluid->_heat;
130
131         if(log)
132         {
133                 /* max density/speed = dydx */
134                 float dydx = 1.0 / (float)speed;
135                 size_t size= fluid->_xRes * fluid->_yRes * fluid->_zRes;
136
137                 for(size_t i = 0; i < size; i++)
138                 {
139                         density[i] *= (1.0 - dydx);
140
141                         if(density[i] < 0.0f)
142                                 density[i] = 0.0f;
143
144                         heat[i] *= (1.0 - dydx);
145
146                         /*if(heat[i] < 0.0f)
147                                 heat[i] = 0.0f;*/
148                 }
149         }
150         else // linear falloff
151         {
152                 /* max density/speed = dydx */
153                 float dydx = 1.0 / (float)speed;
154                 size_t size= fluid->_xRes * fluid->_yRes * fluid->_zRes;
155
156                 for(size_t i = 0; i < size; i++)
157                 {
158                         density[i] -= dydx;
159
160                         if(density[i] < 0.0f)
161                                 density[i] = 0.0f;
162
163                         if(abs(heat[i]) < dydx) heat[i] = 0.0f;
164                         else if (heat[i]>0.0f) heat[i] -= dydx;
165                         else if (heat[i]<0.0f) heat[i] += dydx;
166                                 
167                 }
168         }
169 }
170
171 extern "C" void smoke_dissolve_wavelet(WTURBULENCE *wt, int speed, int log)
172 {
173         float *density = wt->getDensityBig();
174         Vec3Int r = wt->getResBig();
175
176         if(log)
177         {
178                 /* max density/speed = dydx */
179                 float dydx = 1.0 / (float)speed;
180                 size_t size= r[0] * r[1] * r[2];
181
182                 for(size_t i = 0; i < size; i++)
183                 {
184                         density[i] *= (1.0 - dydx);
185
186                         if(density[i] < 0.0f)
187                                 density[i] = 0.0f;
188                 }
189         }
190         else // linear falloff
191         {
192                 /* max density/speed = dydx */
193                 float dydx = 1.0 / (float)speed;
194                 size_t size= r[0] * r[1] * r[2];
195
196                 for(size_t i = 0; i < size; i++)
197                 {
198                         density[i] -= dydx;
199
200                         if(density[i] < 0.0f)
201                                 density[i] = 0.0f;                              
202                 }
203         }
204 }
205
206 extern "C" void smoke_initWaveletBlenderRNA(WTURBULENCE *wt, float *strength)
207 {
208         wt->initBlenderRNA(strength);
209 }
210
211 template < class T > inline T ABS( T a ) {
212         return (0 < a) ? a : -a ;
213 }
214
215 extern "C" void smoke_export(FLUID_3D *fluid, float *dt, float *dx, float **dens, float **densold, float **heat, float **heatold, float **vx, float **vy, float **vz, float **vxold, float **vyold, float **vzold, unsigned char **obstacles)
216 {
217         *dens = fluid->_density;
218         *densold = fluid->_densityOld;
219         *heat = fluid->_heat;
220         *heatold = fluid->_heatOld;
221         *vx = fluid->_xVelocity;
222         *vy = fluid->_yVelocity;
223         *vz = fluid->_zVelocity;
224         *vxold = fluid->_xVelocityOld;
225         *vyold = fluid->_yVelocityOld;
226         *vzold = fluid->_zVelocityOld;
227         *obstacles = fluid->_obstacles;
228         dt = &(fluid->_dt);
229         dx = &(fluid->_dx);
230
231 }
232
233 extern "C" void smoke_turbulence_export(WTURBULENCE *wt, float **dens, float **densold, float **tcu, float **tcv, float **tcw)
234 {
235         if(!wt)
236                 return;
237
238         *dens = wt->_densityBig;
239         *densold = wt->_densityBigOld;
240         *tcu = wt->_tcU;
241         *tcv = wt->_tcV;
242         *tcw = wt->_tcW;
243 }
244
245 extern "C" float *smoke_get_density(FLUID_3D *fluid)
246 {
247         return fluid->_density;
248 }
249
250 extern "C" float *smoke_get_heat(FLUID_3D *fluid)
251 {
252         return fluid->_heat;
253 }
254
255 extern "C" float *smoke_get_velocity_x(FLUID_3D *fluid)
256 {
257         return fluid->_xVelocity;
258 }
259
260 extern "C" float *smoke_get_velocity_y(FLUID_3D *fluid)
261 {
262         return fluid->_yVelocity;
263 }
264
265 extern "C" float *smoke_get_velocity_z(FLUID_3D *fluid)
266 {
267         return fluid->_zVelocity;
268 }
269
270 extern "C" float *smoke_get_force_x(FLUID_3D *fluid)
271 {
272         return fluid->_xForce;
273 }
274
275 extern "C" float *smoke_get_force_y(FLUID_3D *fluid)
276 {
277         return fluid->_yForce;
278 }
279
280 extern "C" float *smoke_get_force_z(FLUID_3D *fluid)
281 {
282         return fluid->_zForce;
283 }
284
285 extern "C" float *smoke_turbulence_get_density(WTURBULENCE *wt)
286 {
287         return wt ? wt->getDensityBig() : NULL;
288 }
289
290 extern "C" void smoke_turbulence_get_res(WTURBULENCE *wt, int *res)
291 {
292         if(wt)
293         {
294                 Vec3Int r = wt->getResBig();
295                 res[0] = r[0];
296                 res[1] = r[1];
297                 res[2] = r[2];
298         }
299 }
300
301 extern "C" unsigned char *smoke_get_obstacle(FLUID_3D *fluid)
302 {
303         return fluid->_obstacles;
304 }
305
306 extern "C" void smoke_turbulence_set_noise(WTURBULENCE *wt, int type)
307 {
308         wt->setNoise(type);
309 }