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 gpu
22  *
23  * GPU fluid drawing functions.
24  */
25 
26 #include <string.h>
27 
28 #include "BLI_math.h"
29 #include "BLI_utildefines.h"
30 
31 #include "DNA_fluid_types.h"
32 #include "DNA_modifier_types.h"
33 
34 #include "MEM_guardedalloc.h"
35 
36 #include "BKE_colorband.h"
37 
38 #include "GPU_texture.h"
39 
40 #include "draw_common.h" /* Own include. */
41 
42 #ifdef WITH_FLUID
43 #  include "manta_fluid_API.h"
44 #endif
45 
46 /* -------------------------------------------------------------------- */
47 /** \name Private API
48  * \{ */
49 
50 #ifdef WITH_FLUID
51 
52 enum {
53   TFUNC_FLAME_SPECTRUM = 0,
54   TFUNC_COLOR_RAMP = 1,
55 };
56 
57 #  define TFUNC_WIDTH 256
58 
create_flame_spectrum_texture(float * data)59 static void create_flame_spectrum_texture(float *data)
60 {
61 #  define FIRE_THRESH 7
62 #  define MAX_FIRE_ALPHA 0.06f
63 #  define FULL_ON_FIRE 100
64 
65   float *spec_pixels = (float *)MEM_mallocN(TFUNC_WIDTH * 4 * 16 * 16 * sizeof(float),
66                                             "spec_pixels");
67 
68   blackbody_temperature_to_rgb_table(data, TFUNC_WIDTH, 1500, 3000);
69 
70   for (int i = 0; i < 16; i++) {
71     for (int j = 0; j < 16; j++) {
72       for (int k = 0; k < TFUNC_WIDTH; k++) {
73         int index = (j * TFUNC_WIDTH * 16 + i * TFUNC_WIDTH + k) * 4;
74         if (k >= FIRE_THRESH) {
75           spec_pixels[index] = (data[k * 4]);
76           spec_pixels[index + 1] = (data[k * 4 + 1]);
77           spec_pixels[index + 2] = (data[k * 4 + 2]);
78           spec_pixels[index + 3] = MAX_FIRE_ALPHA *
79                                    ((k > FULL_ON_FIRE) ?
80                                         1.0f :
81                                         (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH));
82         }
83         else {
84           zero_v4(&spec_pixels[index]);
85         }
86       }
87     }
88   }
89 
90   memcpy(data, spec_pixels, sizeof(float) * 4 * TFUNC_WIDTH);
91 
92   MEM_freeN(spec_pixels);
93 
94 #  undef FIRE_THRESH
95 #  undef MAX_FIRE_ALPHA
96 #  undef FULL_ON_FIRE
97 }
98 
create_color_ramp(const struct ColorBand * coba,float * data)99 static void create_color_ramp(const struct ColorBand *coba, float *data)
100 {
101   for (int i = 0; i < TFUNC_WIDTH; i++) {
102     BKE_colorband_evaluate(coba, (float)i / TFUNC_WIDTH, &data[i * 4]);
103     straight_to_premul_v4(&data[i * 4]);
104   }
105 }
106 
create_transfer_function(int type,const struct ColorBand * coba)107 static GPUTexture *create_transfer_function(int type, const struct ColorBand *coba)
108 {
109   float *data = (float *)MEM_mallocN(sizeof(float[4]) * TFUNC_WIDTH, __func__);
110 
111   switch (type) {
112     case TFUNC_FLAME_SPECTRUM:
113       create_flame_spectrum_texture(data);
114       break;
115     case TFUNC_COLOR_RAMP:
116       create_color_ramp(coba, data);
117       break;
118   }
119 
120   GPUTexture *tex = GPU_texture_create_1d("transf_func", TFUNC_WIDTH, 1, GPU_SRGB8_A8, data);
121 
122   MEM_freeN(data);
123 
124   return tex;
125 }
126 
swizzle_texture_channel_single(GPUTexture * tex)127 static void swizzle_texture_channel_single(GPUTexture *tex)
128 {
129   /* Swizzle texture channels so that we get useful RGBA values when sampling
130    * a texture with fewer channels, e.g. when using density as color. */
131   GPU_texture_swizzle_set(tex, "rrr1");
132 }
133 
rescale_3d(const int dim[3],const int final_dim[3],int channels,const float * fpixels)134 static float *rescale_3d(const int dim[3],
135                          const int final_dim[3],
136                          int channels,
137                          const float *fpixels)
138 {
139   const uint w = dim[0], h = dim[1], d = dim[2];
140   const uint fw = final_dim[0], fh = final_dim[1], fd = final_dim[2];
141   const uint xf = w / fw, yf = h / fh, zf = d / fd;
142   const uint pixel_count = fw * fh * fd;
143   float *nfpixels = (float *)MEM_mallocN(channels * sizeof(float) * pixel_count, __func__);
144 
145   if (nfpixels) {
146     printf("Performance: You need to scale a 3D texture, feel the pain!\n");
147 
148     for (uint k = 0; k < fd; k++) {
149       for (uint j = 0; j < fh; j++) {
150         for (uint i = 0; i < fw; i++) {
151           /* Obviously doing nearest filtering here,
152            * it's going to be slow in any case, let's not make it worse. */
153           float xb = i * xf;
154           float yb = j * yf;
155           float zb = k * zf;
156           uint offset = k * (fw * fh) + i * fh + j;
157           uint offset_orig = (zb) * (w * h) + (xb)*h + (yb);
158 
159           if (channels == 4) {
160             nfpixels[offset * 4] = fpixels[offset_orig * 4];
161             nfpixels[offset * 4 + 1] = fpixels[offset_orig * 4 + 1];
162             nfpixels[offset * 4 + 2] = fpixels[offset_orig * 4 + 2];
163             nfpixels[offset * 4 + 3] = fpixels[offset_orig * 4 + 3];
164           }
165           else if (channels == 1) {
166             nfpixels[offset] = fpixels[offset_orig];
167           }
168           else {
169             BLI_assert(0);
170           }
171         }
172       }
173     }
174   }
175   return nfpixels;
176 }
177 
178 /* Will resize input to fit GL system limits. */
create_volume_texture(const int dim[3],eGPUTextureFormat texture_format,eGPUDataFormat data_format,const void * data)179 static GPUTexture *create_volume_texture(const int dim[3],
180                                          eGPUTextureFormat texture_format,
181                                          eGPUDataFormat data_format,
182                                          const void *data)
183 {
184   GPUTexture *tex = NULL;
185   int final_dim[3] = {UNPACK3(dim)};
186 
187   if (data == NULL) {
188     return NULL;
189   }
190 
191   while (1) {
192     tex = GPU_texture_create_3d(
193         "volume", UNPACK3(final_dim), 1, texture_format, data_format, NULL);
194 
195     if (tex != NULL) {
196       break;
197     }
198 
199     if (final_dim[0] == 1 && final_dim[1] == 1 && final_dim[2] == 1) {
200       break;
201     }
202 
203     for (int i = 0; i < 3; i++) {
204       final_dim[i] = max_ii(1, final_dim[i] / 2);
205     }
206   }
207 
208   if (tex == NULL) {
209     printf("Error: Could not create 3D texture.\n");
210     tex = GPU_texture_create_error(3, false);
211   }
212   else if (equals_v3v3_int(dim, final_dim)) {
213     /* No need to resize, just upload the data. */
214     GPU_texture_update_sub(tex, data_format, data, 0, 0, 0, UNPACK3(final_dim));
215   }
216   else if (data_format != GPU_DATA_FLOAT) {
217     printf("Error: Could not allocate 3D texture and not attempting to rescale non-float data.\n");
218     tex = GPU_texture_create_error(3, false);
219   }
220   else {
221     /* We need to resize the input. */
222     int channels = (ELEM(texture_format, GPU_R8, GPU_R16F, GPU_R32F)) ? 1 : 4;
223     float *rescaled_data = rescale_3d(dim, final_dim, channels, data);
224     if (rescaled_data) {
225       GPU_texture_update_sub(tex, GPU_DATA_FLOAT, rescaled_data, 0, 0, 0, UNPACK3(final_dim));
226       MEM_freeN(rescaled_data);
227     }
228     else {
229       printf("Error: Could not allocate rescaled 3d texture!\n");
230       GPU_texture_free(tex);
231       tex = GPU_texture_create_error(3, false);
232     }
233   }
234   return tex;
235 }
236 
create_field_texture(FluidDomainSettings * fds,bool single_precision)237 static GPUTexture *create_field_texture(FluidDomainSettings *fds, bool single_precision)
238 {
239   void *field = NULL;
240   eGPUDataFormat data_format = GPU_DATA_FLOAT;
241   eGPUTextureFormat texture_format = GPU_R8;
242 
243   if (single_precision) {
244     texture_format = GPU_R32F;
245   }
246 
247   switch (fds->coba_field) {
248     case FLUID_DOMAIN_FIELD_DENSITY:
249       field = manta_smoke_get_density(fds->fluid);
250       break;
251     case FLUID_DOMAIN_FIELD_HEAT:
252       field = manta_smoke_get_heat(fds->fluid);
253       break;
254     case FLUID_DOMAIN_FIELD_FUEL:
255       field = manta_smoke_get_fuel(fds->fluid);
256       break;
257     case FLUID_DOMAIN_FIELD_REACT:
258       field = manta_smoke_get_react(fds->fluid);
259       break;
260     case FLUID_DOMAIN_FIELD_FLAME:
261       field = manta_smoke_get_flame(fds->fluid);
262       break;
263     case FLUID_DOMAIN_FIELD_VELOCITY_X:
264       field = manta_get_velocity_x(fds->fluid);
265       break;
266     case FLUID_DOMAIN_FIELD_VELOCITY_Y:
267       field = manta_get_velocity_y(fds->fluid);
268       break;
269     case FLUID_DOMAIN_FIELD_VELOCITY_Z:
270       field = manta_get_velocity_z(fds->fluid);
271       break;
272     case FLUID_DOMAIN_FIELD_COLOR_R:
273       field = manta_smoke_get_color_r(fds->fluid);
274       break;
275     case FLUID_DOMAIN_FIELD_COLOR_G:
276       field = manta_smoke_get_color_g(fds->fluid);
277       break;
278     case FLUID_DOMAIN_FIELD_COLOR_B:
279       field = manta_smoke_get_color_b(fds->fluid);
280       break;
281     case FLUID_DOMAIN_FIELD_FORCE_X:
282       field = manta_get_force_x(fds->fluid);
283       break;
284     case FLUID_DOMAIN_FIELD_FORCE_Y:
285       field = manta_get_force_y(fds->fluid);
286       break;
287     case FLUID_DOMAIN_FIELD_FORCE_Z:
288       field = manta_get_force_z(fds->fluid);
289       break;
290     case FLUID_DOMAIN_FIELD_PHI:
291       field = manta_get_phi(fds->fluid);
292       texture_format = GPU_R16F;
293       break;
294     case FLUID_DOMAIN_FIELD_PHI_IN:
295       field = manta_get_phi_in(fds->fluid);
296       texture_format = GPU_R16F;
297       break;
298     case FLUID_DOMAIN_FIELD_PHI_OUT:
299       field = manta_get_phiout_in(fds->fluid);
300       texture_format = GPU_R16F;
301       break;
302     case FLUID_DOMAIN_FIELD_PHI_OBSTACLE:
303       field = manta_get_phiobs_in(fds->fluid);
304       texture_format = GPU_R16F;
305       break;
306     case FLUID_DOMAIN_FIELD_FLAGS:
307       field = manta_smoke_get_flags(fds->fluid);
308       data_format = GPU_DATA_INT;
309       texture_format = GPU_R8UI;
310       break;
311     case FLUID_DOMAIN_FIELD_PRESSURE:
312       field = manta_get_pressure(fds->fluid);
313       texture_format = GPU_R16F;
314       break;
315     default:
316       return NULL;
317   }
318 
319   if (field == NULL) {
320     return NULL;
321   }
322 
323   GPUTexture *tex = create_volume_texture(fds->res, texture_format, data_format, field);
324   swizzle_texture_channel_single(tex);
325   return tex;
326 }
327 
create_density_texture(FluidDomainSettings * fds,int highres)328 static GPUTexture *create_density_texture(FluidDomainSettings *fds, int highres)
329 {
330   int *dim = (highres) ? fds->res_noise : fds->res;
331 
332   float *data;
333   if (highres) {
334     data = manta_noise_get_density(fds->fluid);
335   }
336   else {
337     data = manta_smoke_get_density(fds->fluid);
338   }
339 
340   if (data == NULL) {
341     return NULL;
342   }
343 
344   GPUTexture *tex = create_volume_texture(dim, GPU_R8, GPU_DATA_FLOAT, data);
345   swizzle_texture_channel_single(tex);
346   return tex;
347 }
348 
create_color_texture(FluidDomainSettings * fds,int highres)349 static GPUTexture *create_color_texture(FluidDomainSettings *fds, int highres)
350 {
351   const bool has_color = (highres) ? manta_noise_has_colors(fds->fluid) :
352                                      manta_smoke_has_colors(fds->fluid);
353 
354   if (!has_color) {
355     return NULL;
356   }
357 
358   int cell_count = (highres) ? manta_noise_get_cells(fds->fluid) : fds->total_cells;
359   int *dim = (highres) ? fds->res_noise : fds->res;
360   float *data = (float *)MEM_callocN(sizeof(float) * cell_count * 4, "smokeColorTexture");
361 
362   if (data == NULL) {
363     return NULL;
364   }
365 
366   if (highres) {
367     manta_noise_get_rgba(fds->fluid, data, 0);
368   }
369   else {
370     manta_smoke_get_rgba(fds->fluid, data, 0);
371   }
372 
373   GPUTexture *tex = create_volume_texture(dim, GPU_RGBA8, GPU_DATA_FLOAT, data);
374 
375   MEM_freeN(data);
376 
377   return tex;
378 }
379 
create_flame_texture(FluidDomainSettings * fds,int highres)380 static GPUTexture *create_flame_texture(FluidDomainSettings *fds, int highres)
381 {
382   float *source = NULL;
383   const bool has_fuel = (highres) ? manta_noise_has_fuel(fds->fluid) :
384                                     manta_smoke_has_fuel(fds->fluid);
385   int *dim = (highres) ? fds->res_noise : fds->res;
386 
387   if (!has_fuel) {
388     return NULL;
389   }
390 
391   if (highres) {
392     source = manta_noise_get_flame(fds->fluid);
393   }
394   else {
395     source = manta_smoke_get_flame(fds->fluid);
396   }
397 
398   GPUTexture *tex = create_volume_texture(dim, GPU_R8, GPU_DATA_FLOAT, source);
399   swizzle_texture_channel_single(tex);
400   return tex;
401 }
402 
get_smoke_velocity_field(FluidDomainSettings * fds,float ** r_velocity_x,float ** r_velocity_y,float ** r_velocity_z)403 static bool get_smoke_velocity_field(FluidDomainSettings *fds,
404                                      float **r_velocity_x,
405                                      float **r_velocity_y,
406                                      float **r_velocity_z)
407 {
408   const char vector_field = fds->vector_field;
409   switch ((FLUID_DisplayVectorField)vector_field) {
410     case FLUID_DOMAIN_VECTOR_FIELD_VELOCITY:
411       *r_velocity_x = manta_get_velocity_x(fds->fluid);
412       *r_velocity_y = manta_get_velocity_y(fds->fluid);
413       *r_velocity_z = manta_get_velocity_z(fds->fluid);
414       break;
415     case FLUID_DOMAIN_VECTOR_FIELD_GUIDE_VELOCITY:
416       *r_velocity_x = manta_get_guide_velocity_x(fds->fluid);
417       *r_velocity_y = manta_get_guide_velocity_y(fds->fluid);
418       *r_velocity_z = manta_get_guide_velocity_z(fds->fluid);
419       break;
420     case FLUID_DOMAIN_VECTOR_FIELD_FORCE:
421       *r_velocity_x = manta_get_force_x(fds->fluid);
422       *r_velocity_y = manta_get_force_y(fds->fluid);
423       *r_velocity_z = manta_get_force_z(fds->fluid);
424       break;
425   }
426 
427   return *r_velocity_x && *r_velocity_y && *r_velocity_z;
428 }
429 
430 #endif /* WITH_FLUID */
431 
432 /** \} */
433 
434 /* -------------------------------------------------------------------- */
435 /** \name Public API
436  * \{ */
437 
DRW_smoke_free(FluidModifierData * fmd)438 void DRW_smoke_free(FluidModifierData *fmd)
439 {
440   if (fmd->type & MOD_FLUID_TYPE_DOMAIN && fmd->domain) {
441     if (fmd->domain->tex_density) {
442       GPU_texture_free(fmd->domain->tex_density);
443       fmd->domain->tex_density = NULL;
444     }
445 
446     if (fmd->domain->tex_color) {
447       GPU_texture_free(fmd->domain->tex_color);
448       fmd->domain->tex_color = NULL;
449     }
450 
451     if (fmd->domain->tex_shadow) {
452       GPU_texture_free(fmd->domain->tex_shadow);
453       fmd->domain->tex_shadow = NULL;
454     }
455 
456     if (fmd->domain->tex_flame) {
457       GPU_texture_free(fmd->domain->tex_flame);
458       fmd->domain->tex_flame = NULL;
459     }
460 
461     if (fmd->domain->tex_flame_coba) {
462       GPU_texture_free(fmd->domain->tex_flame_coba);
463       fmd->domain->tex_flame_coba = NULL;
464     }
465 
466     if (fmd->domain->tex_coba) {
467       GPU_texture_free(fmd->domain->tex_coba);
468       fmd->domain->tex_coba = NULL;
469     }
470 
471     if (fmd->domain->tex_field) {
472       GPU_texture_free(fmd->domain->tex_field);
473       fmd->domain->tex_field = NULL;
474     }
475   }
476 }
477 
DRW_smoke_ensure_coba_field(FluidModifierData * fmd)478 void DRW_smoke_ensure_coba_field(FluidModifierData *fmd)
479 {
480 #ifndef WITH_FLUID
481   UNUSED_VARS(fmd);
482 #else
483   if (fmd->type & MOD_FLUID_TYPE_DOMAIN) {
484     FluidDomainSettings *fds = fmd->domain;
485 
486     if (!fds->tex_field) {
487       fds->tex_field = create_field_texture(fds, false);
488     }
489     if (!fds->tex_coba && !ELEM(fds->coba_field,
490                                 FLUID_DOMAIN_FIELD_PHI,
491                                 FLUID_DOMAIN_FIELD_PHI_IN,
492                                 FLUID_DOMAIN_FIELD_PHI_OUT,
493                                 FLUID_DOMAIN_FIELD_PHI_OBSTACLE,
494                                 FLUID_DOMAIN_FIELD_FLAGS,
495                                 FLUID_DOMAIN_FIELD_PRESSURE)) {
496       fds->tex_coba = create_transfer_function(TFUNC_COLOR_RAMP, fds->coba);
497     }
498   }
499 #endif
500 }
501 
DRW_smoke_ensure(FluidModifierData * fmd,int highres)502 void DRW_smoke_ensure(FluidModifierData *fmd, int highres)
503 {
504 #ifndef WITH_FLUID
505   UNUSED_VARS(fmd, highres);
506 #else
507   if (fmd->type & MOD_FLUID_TYPE_DOMAIN) {
508     FluidDomainSettings *fds = fmd->domain;
509 
510     if (!fds->tex_density) {
511       fds->tex_density = create_density_texture(fds, highres);
512     }
513     if (!fds->tex_color) {
514       fds->tex_color = create_color_texture(fds, highres);
515     }
516     if (!fds->tex_flame) {
517       fds->tex_flame = create_flame_texture(fds, highres);
518     }
519     if (!fds->tex_flame_coba && fds->tex_flame) {
520       fds->tex_flame_coba = create_transfer_function(TFUNC_FLAME_SPECTRUM, NULL);
521     }
522     if (!fds->tex_shadow) {
523       fds->tex_shadow = create_volume_texture(
524           fds->res, GPU_R8, GPU_DATA_FLOAT, manta_smoke_get_shadow(fds->fluid));
525     }
526   }
527 #endif /* WITH_FLUID */
528 }
529 
DRW_smoke_ensure_velocity(FluidModifierData * fmd)530 void DRW_smoke_ensure_velocity(FluidModifierData *fmd)
531 {
532 #ifndef WITH_FLUID
533   UNUSED_VARS(fmd);
534 #else
535   if (fmd->type & MOD_FLUID_TYPE_DOMAIN) {
536     FluidDomainSettings *fds = fmd->domain;
537     float *vel_x = NULL, *vel_y = NULL, *vel_z = NULL;
538 
539     if (!get_smoke_velocity_field(fds, &vel_x, &vel_y, &vel_z)) {
540       fds->vector_field = FLUID_DOMAIN_VECTOR_FIELD_VELOCITY;
541       get_smoke_velocity_field(fds, &vel_x, &vel_y, &vel_z);
542     }
543 
544     if (ELEM(NULL, vel_x, vel_y, vel_z)) {
545       return;
546     }
547 
548     if (!fds->tex_velocity_x) {
549       fds->tex_velocity_x = GPU_texture_create_3d(
550           "velx", UNPACK3(fds->res), 1, GPU_R16F, GPU_DATA_FLOAT, vel_x);
551       fds->tex_velocity_y = GPU_texture_create_3d(
552           "vely", UNPACK3(fds->res), 1, GPU_R16F, GPU_DATA_FLOAT, vel_y);
553       fds->tex_velocity_z = GPU_texture_create_3d(
554           "velz", UNPACK3(fds->res), 1, GPU_R16F, GPU_DATA_FLOAT, vel_z);
555     }
556   }
557 #endif /* WITH_FLUID */
558 }
559 
DRW_fluid_ensure_flags(FluidModifierData * fmd)560 void DRW_fluid_ensure_flags(FluidModifierData *fmd)
561 {
562 #ifndef WITH_FLUID
563   UNUSED_VARS(fmd);
564 #else
565   if (fmd->type & MOD_FLUID_TYPE_DOMAIN) {
566     FluidDomainSettings *fds = fmd->domain;
567     if (!fds->tex_flags) {
568       fds->tex_flags = create_volume_texture(
569           fds->res, GPU_R8UI, GPU_DATA_INT, manta_smoke_get_flags(fds->fluid));
570 
571       swizzle_texture_channel_single(fds->tex_flags);
572     }
573   }
574 #endif /* WITH_FLUID */
575 }
576 
DRW_fluid_ensure_range_field(FluidModifierData * fmd)577 void DRW_fluid_ensure_range_field(FluidModifierData *fmd)
578 {
579 #ifndef WITH_FLUID
580   UNUSED_VARS(fmd);
581 #else
582   if (fmd->type & MOD_FLUID_TYPE_DOMAIN) {
583     FluidDomainSettings *fds = fmd->domain;
584 
585     if (!fds->tex_range_field) {
586       fds->tex_range_field = create_field_texture(fds, true);
587     }
588   }
589 #endif /* WITH_FLUID */
590 }
591 
592 /* TODO Unify with the other GPU_free_smoke. */
DRW_smoke_free_velocity(FluidModifierData * fmd)593 void DRW_smoke_free_velocity(FluidModifierData *fmd)
594 {
595   if (fmd->type & MOD_FLUID_TYPE_DOMAIN && fmd->domain) {
596     if (fmd->domain->tex_velocity_x) {
597       GPU_texture_free(fmd->domain->tex_velocity_x);
598     }
599 
600     if (fmd->domain->tex_velocity_y) {
601       GPU_texture_free(fmd->domain->tex_velocity_y);
602     }
603 
604     if (fmd->domain->tex_velocity_z) {
605       GPU_texture_free(fmd->domain->tex_velocity_z);
606     }
607 
608     if (fmd->domain->tex_flags) {
609       GPU_texture_free(fmd->domain->tex_flags);
610     }
611 
612     if (fmd->domain->tex_range_field) {
613       GPU_texture_free(fmd->domain->tex_range_field);
614     }
615 
616     fmd->domain->tex_velocity_x = NULL;
617     fmd->domain->tex_velocity_y = NULL;
618     fmd->domain->tex_velocity_z = NULL;
619     fmd->domain->tex_flags = NULL;
620     fmd->domain->tex_range_field = NULL;
621   }
622 }
623 
624 /** \} */
625