Blender V5.0
ocean.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11
12#include <algorithm>
13#include <cmath>
14#include <cstdlib>
15
16#include <cstring>
17
18#include "MEM_guardedalloc.h"
19
20#include "DNA_modifier_types.h"
21#include "DNA_scene_types.h"
22
23#include "BLI_math_vector.h"
24#include "BLI_path_utils.hh"
25#include "BLI_rand.h"
26#include "BLI_task.h"
27#include "BLI_utildefines.h"
28
29#include "BKE_image.hh"
30#include "BKE_image_format.hh"
31#include "BKE_ocean.h"
32#include "ocean_intern.h"
33
34#include "IMB_imbuf.hh"
35#include "IMB_imbuf_types.hh"
36
37#include "RE_texture.h"
38
39#include "BLI_hash.h"
40
41#ifdef WITH_OCEANSIM
42
43/* Ocean code */
44
45static float nextfr(RNG *rng, float min, float max)
46{
47 return BLI_rng_get_float(rng) * (min - max) + max;
48}
49
50static float gaussRand(RNG *rng)
51{
52 /* NOTE: to avoid numerical problems with very small numbers, we make these variables
53 * single-precision floats, but later we call the double-precision log() and sqrt() functions
54 * instead of logf() and sqrtf(). */
55 float x;
56 float y;
57 float length2;
58
59 do {
60 x = nextfr(rng, -1, 1);
61 y = nextfr(rng, -1, 1);
62 length2 = x * x + y * y;
63 } while (length2 >= 1 || length2 == 0);
64
65 return x * sqrtf(-2.0f * logf(length2) / length2);
66}
67
71MINLINE float catrom(float p0, float p1, float p2, float p3, float f)
72{
73 return 0.5f * ((2.0f * p1) + (-p0 + p2) * f + (2.0f * p0 - 5.0f * p1 + 4.0f * p2 - p3) * f * f +
74 (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * f * f * f);
75}
76
77MINLINE float omega(float k, float depth)
78{
79 return sqrtf(GRAVITY * k * tanhf(k * depth));
80}
81
82/* modified Phillips spectrum */
83static float Ph(Ocean *o, float kx, float kz)
84{
85 float tmp;
86 float k2 = kx * kx + kz * kz;
87
88 if (k2 == 0.0f) {
89 return 0.0f; /* no DC component */
90 }
91
92 /* damp out the waves going in the direction opposite the wind */
93 tmp = (o->_wx * kx + o->_wz * kz) / sqrtf(k2);
94 if (tmp < 0) {
95 tmp *= o->_damp_reflections;
96 }
97
98 return o->_A * expf(-1.0f / (k2 * (o->_L * o->_L))) * expf(-k2 * (o->_l * o->_l)) *
99 powf(fabsf(tmp), o->_wind_alignment) / (k2 * k2);
100}
101
102static void compute_eigenstuff(OceanResult *ocr, float jxx, float jzz, float jxz)
103{
104 float a, b, qplus, qminus;
105 a = jxx + jzz;
106 b = sqrt((jxx - jzz) * (jxx - jzz) + 4 * jxz * jxz);
107
108 ocr->Jminus = 0.5f * (a - b);
109 ocr->Jplus = 0.5f * (a + b);
110
111 qplus = (ocr->Jplus - jxx) / jxz;
112 qminus = (ocr->Jminus - jxx) / jxz;
113
114 a = sqrt(1 + qplus * qplus);
115 b = sqrt(1 + qminus * qminus);
116
117 ocr->Eplus[0] = 1.0f / a;
118 ocr->Eplus[1] = 0.0f;
119 ocr->Eplus[2] = qplus / a;
120
121 ocr->Eminus[0] = 1.0f / b;
122 ocr->Eminus[1] = 0.0f;
123 ocr->Eminus[2] = qminus / b;
124}
125
126/*
127 * instead of Complex.h
128 * in fftw.h "fftw_complex" typedefed as double[2]
129 * below you can see functions are needed to work with such complex numbers.
130 */
131static void init_complex(fftw_complex cmpl, float real, float image)
132{
133 cmpl[0] = real;
134 cmpl[1] = image;
135}
136
137static void add_comlex_c(fftw_complex res, const fftw_complex cmpl1, const fftw_complex cmpl2)
138{
139 res[0] = cmpl1[0] + cmpl2[0];
140 res[1] = cmpl1[1] + cmpl2[1];
141}
142
143static void mul_complex_f(fftw_complex res, const fftw_complex cmpl, float f)
144{
145 res[0] = cmpl[0] * double(f);
146 res[1] = cmpl[1] * double(f);
147}
148
149static void mul_complex_c(fftw_complex res, const fftw_complex cmpl1, const fftw_complex cmpl2)
150{
151 fftwf_complex temp;
152 temp[0] = cmpl1[0] * cmpl2[0] - cmpl1[1] * cmpl2[1];
153 temp[1] = cmpl1[0] * cmpl2[1] + cmpl1[1] * cmpl2[0];
154 res[0] = temp[0];
155 res[1] = temp[1];
156}
157
158static float real_c(fftw_complex cmpl)
159{
160 return cmpl[0];
161}
162
163static float image_c(fftw_complex cmpl)
164{
165 return cmpl[1];
166}
167
168static void conj_complex(fftw_complex res, const fftw_complex cmpl1)
169{
170 res[0] = cmpl1[0];
171 res[1] = -cmpl1[1];
172}
173
174static void exp_complex(fftw_complex res, fftw_complex cmpl)
175{
176 float r = expf(cmpl[0]);
177
178 res[0] = cosf(cmpl[1]) * r;
179 res[1] = sinf(cmpl[1]) * r;
180}
181
182float BKE_ocean_jminus_to_foam(float jminus, float coverage)
183{
184 float foam = jminus * -0.005f + coverage;
185 CLAMP(foam, 0.0f, 1.0f);
186 return foam;
187}
188
189void BKE_ocean_eval_uv(Ocean *oc, OceanResult *ocr, float u, float v)
190{
191 int i0, i1, j0, j1;
192 float frac_x, frac_z;
193 float uu, vv;
194
195 /* first wrap the texture so 0 <= (u, v) < 1 */
196 u = fmodf(u, 1.0f);
197 v = fmodf(v, 1.0f);
198
199 if (u < 0) {
200 u += 1.0f;
201 }
202 if (v < 0) {
203 v += 1.0f;
204 }
205
206 BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ);
207
208 uu = u * oc->_M;
209 vv = v * oc->_N;
210
211 i0 = int(floor(uu));
212 j0 = int(floor(vv));
213
214 i1 = (i0 + 1);
215 j1 = (j0 + 1);
216
217 frac_x = uu - i0;
218 frac_z = vv - j0;
219
220 i0 = i0 % oc->_M;
221 j0 = j0 % oc->_N;
222
223 i1 = i1 % oc->_M;
224 j1 = j1 % oc->_N;
225
226# define BILERP(m) \
227 interpf(interpf(m[i1 * oc->_N + j1], m[i0 * oc->_N + j1], frac_x), \
228 interpf(m[i1 * oc->_N + j0], m[i0 * oc->_N + j0], frac_x), \
229 frac_z)
230
231 {
232 if (oc->_do_disp_y) {
233 ocr->disp[1] = BILERP(oc->_disp_y);
234 }
235
236 if (oc->_do_normals) {
237 ocr->normal[0] = BILERP(oc->_N_x);
238 ocr->normal[1] = oc->_N_y /* BILERP(oc->_N_y) (MEM01) */;
239 ocr->normal[2] = BILERP(oc->_N_z);
240 }
241
242 if (oc->_do_chop) {
243 ocr->disp[0] = BILERP(oc->_disp_x);
244 ocr->disp[2] = BILERP(oc->_disp_z);
245 }
246 else {
247 ocr->disp[0] = 0.0;
248 ocr->disp[2] = 0.0;
249 }
250
251 if (oc->_do_jacobian) {
252 compute_eigenstuff(ocr, BILERP(oc->_Jxx), BILERP(oc->_Jzz), BILERP(oc->_Jxz));
253 }
254 }
255# undef BILERP
256
257 BLI_rw_mutex_unlock(&oc->oceanmutex);
258}
259
260void BKE_ocean_eval_uv_catrom(Ocean *oc, OceanResult *ocr, float u, float v)
261{
262 int i0, i1, i2, i3, j0, j1, j2, j3;
263 float frac_x, frac_z;
264 float uu, vv;
265
266 /* first wrap the texture so 0 <= (u, v) < 1 */
267 u = fmod(u, 1.0f);
268 v = fmod(v, 1.0f);
269
270 if (u < 0) {
271 u += 1.0f;
272 }
273 if (v < 0) {
274 v += 1.0f;
275 }
276
277 BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ);
278
279 uu = u * oc->_M;
280 vv = v * oc->_N;
281
282 i1 = int(floor(uu));
283 j1 = int(floor(vv));
284
285 i2 = (i1 + 1);
286 j2 = (j1 + 1);
287
288 frac_x = uu - i1;
289 frac_z = vv - j1;
290
291 i1 = i1 % oc->_M;
292 j1 = j1 % oc->_N;
293
294 i2 = i2 % oc->_M;
295 j2 = j2 % oc->_N;
296
297 i0 = (i1 - 1);
298 i3 = (i2 + 1);
299 i0 = i0 < 0 ? i0 + oc->_M : i0;
300 i3 = i3 >= oc->_M ? i3 - oc->_M : i3;
301
302 j0 = (j1 - 1);
303 j3 = (j2 + 1);
304 j0 = j0 < 0 ? j0 + oc->_N : j0;
305 j3 = j3 >= oc->_N ? j3 - oc->_N : j3;
306
307# define INTERP(m) \
308 catrom(catrom(m[i0 * oc->_N + j0], \
309 m[i1 * oc->_N + j0], \
310 m[i2 * oc->_N + j0], \
311 m[i3 * oc->_N + j0], \
312 frac_x), \
313 catrom(m[i0 * oc->_N + j1], \
314 m[i1 * oc->_N + j1], \
315 m[i2 * oc->_N + j1], \
316 m[i3 * oc->_N + j1], \
317 frac_x), \
318 catrom(m[i0 * oc->_N + j2], \
319 m[i1 * oc->_N + j2], \
320 m[i2 * oc->_N + j2], \
321 m[i3 * oc->_N + j2], \
322 frac_x), \
323 catrom(m[i0 * oc->_N + j3], \
324 m[i1 * oc->_N + j3], \
325 m[i2 * oc->_N + j3], \
326 m[i3 * oc->_N + j3], \
327 frac_x), \
328 frac_z)
329
330 {
331 if (oc->_do_disp_y) {
332 ocr->disp[1] = INTERP(oc->_disp_y);
333 }
334 if (oc->_do_normals) {
335 ocr->normal[0] = INTERP(oc->_N_x);
336 ocr->normal[1] = oc->_N_y /* INTERP(oc->_N_y) (MEM01) */;
337 ocr->normal[2] = INTERP(oc->_N_z);
338 }
339 if (oc->_do_chop) {
340 ocr->disp[0] = INTERP(oc->_disp_x);
341 ocr->disp[2] = INTERP(oc->_disp_z);
342 }
343 else {
344 ocr->disp[0] = 0.0;
345 ocr->disp[2] = 0.0;
346 }
347
348 if (oc->_do_jacobian) {
349 compute_eigenstuff(ocr, INTERP(oc->_Jxx), INTERP(oc->_Jzz), INTERP(oc->_Jxz));
350 }
351 }
352# undef INTERP
353
354 BLI_rw_mutex_unlock(&oc->oceanmutex);
355}
356
357void BKE_ocean_eval_xz(Ocean *oc, OceanResult *ocr, float x, float z)
358{
359 BKE_ocean_eval_uv(oc, ocr, x / oc->_Lx, z / oc->_Lz);
360}
361
362void BKE_ocean_eval_xz_catrom(Ocean *oc, OceanResult *ocr, float x, float z)
363{
364 BKE_ocean_eval_uv_catrom(oc, ocr, x / oc->_Lx, z / oc->_Lz);
365}
366
367void BKE_ocean_eval_ij(Ocean *oc, OceanResult *ocr, int i, int j)
368{
369 BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ);
370
371 i = abs(i) % oc->_M;
372 j = abs(j) % oc->_N;
373
374 ocr->disp[1] = oc->_do_disp_y ? float(oc->_disp_y[i * oc->_N + j]) : 0.0f;
375
376 if (oc->_do_chop) {
377 ocr->disp[0] = oc->_disp_x[i * oc->_N + j];
378 ocr->disp[2] = oc->_disp_z[i * oc->_N + j];
379 }
380 else {
381 ocr->disp[0] = 0.0f;
382 ocr->disp[2] = 0.0f;
383 }
384
385 if (oc->_do_normals) {
386 ocr->normal[0] = oc->_N_x[i * oc->_N + j];
387 ocr->normal[1] = oc->_N_y /* oc->_N_y[i * oc->_N + j] (MEM01) */;
388 ocr->normal[2] = oc->_N_z[i * oc->_N + j];
389
390 normalize_v3(ocr->normal);
391 }
392
393 if (oc->_do_jacobian) {
394 compute_eigenstuff(
395 ocr, oc->_Jxx[i * oc->_N + j], oc->_Jzz[i * oc->_N + j], oc->_Jxz[i * oc->_N + j]);
396 }
397
398 BLI_rw_mutex_unlock(&oc->oceanmutex);
399}
400
401struct OceanSimulateData {
402 Ocean *o;
403 float t;
404 float scale;
405 float chop_amount;
406};
407
408static void ocean_compute_htilda(void *__restrict userdata,
409 const int i,
410 const TaskParallelTLS *__restrict /*tls*/)
411{
412 OceanSimulateData *osd = static_cast<OceanSimulateData *>(userdata);
413 const Ocean *o = osd->o;
414 const float scale = osd->scale;
415 const float t = osd->t;
416
417 int j;
418
419 /* Note the <= _N/2 here, see the FFTW documentation
420 * about the mechanics of the complex->real fft storage. */
421 for (j = 0; j <= o->_N / 2; j++) {
422 fftw_complex exp_param1;
423 fftw_complex exp_param2;
424 fftw_complex conj_param;
425
426 init_complex(exp_param1, 0.0, omega(o->_k[i * (1 + o->_N / 2) + j], o->_depth) * t);
427 init_complex(exp_param2, 0.0, -omega(o->_k[i * (1 + o->_N / 2) + j], o->_depth) * t);
428 exp_complex(exp_param1, exp_param1);
429 exp_complex(exp_param2, exp_param2);
430 conj_complex(conj_param, o->_h0_minus[i * o->_N + j]);
431
432 mul_complex_c(exp_param1, o->_h0[i * o->_N + j], exp_param1);
433 mul_complex_c(exp_param2, conj_param, exp_param2);
434
435 add_comlex_c(o->_htilda[i * (1 + o->_N / 2) + j], exp_param1, exp_param2);
436 mul_complex_f(o->_fft_in[i * (1 + o->_N / 2) + j], o->_htilda[i * (1 + o->_N / 2) + j], scale);
437 }
438}
439
440static void ocean_compute_displacement_y(TaskPool *__restrict pool, void * /*taskdata*/)
441{
442 OceanSimulateData *osd = static_cast<OceanSimulateData *>(BLI_task_pool_user_data(pool));
443 const Ocean *o = osd->o;
444
445 fftw_execute(o->_disp_y_plan);
446}
447
448static void ocean_compute_displacement_x(TaskPool *__restrict pool, void * /*taskdata*/)
449{
450 OceanSimulateData *osd = static_cast<OceanSimulateData *>(BLI_task_pool_user_data(pool));
451 const Ocean *o = osd->o;
452 const float scale = osd->scale;
453 const float chop_amount = osd->chop_amount;
454 int i, j;
455
456 for (i = 0; i < o->_M; i++) {
457 for (j = 0; j <= o->_N / 2; j++) {
458 fftw_complex mul_param;
459 fftw_complex minus_i;
460
461 init_complex(minus_i, 0.0, -1.0);
462 init_complex(mul_param, -scale, 0);
463 mul_complex_f(mul_param, mul_param, chop_amount);
464 mul_complex_c(mul_param, mul_param, minus_i);
465 mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
466 mul_complex_f(mul_param,
467 mul_param,
468 ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ?
469 0.0f :
470 o->_kx[i] / o->_k[i * (1 + o->_N / 2) + j]));
471 init_complex(o->_fft_in_x[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
472 }
473 }
474 fftw_execute(o->_disp_x_plan);
475}
476
477static void ocean_compute_displacement_z(TaskPool *__restrict pool, void * /*taskdata*/)
478{
479 OceanSimulateData *osd = static_cast<OceanSimulateData *>(BLI_task_pool_user_data(pool));
480 const Ocean *o = osd->o;
481 const float scale = osd->scale;
482 const float chop_amount = osd->chop_amount;
483 int i, j;
484
485 for (i = 0; i < o->_M; i++) {
486 for (j = 0; j <= o->_N / 2; j++) {
487 fftw_complex mul_param;
488 fftw_complex minus_i;
489
490 init_complex(minus_i, 0.0, -1.0);
491 init_complex(mul_param, -scale, 0);
492 mul_complex_f(mul_param, mul_param, chop_amount);
493 mul_complex_c(mul_param, mul_param, minus_i);
494 mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
495 mul_complex_f(mul_param,
496 mul_param,
497 ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ?
498 0.0f :
499 o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j]));
500 init_complex(o->_fft_in_z[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
501 }
502 }
503 fftw_execute(o->_disp_z_plan);
504}
505
506static void ocean_compute_jacobian_jxx(TaskPool *__restrict pool, void * /*taskdata*/)
507{
508 OceanSimulateData *osd = static_cast<OceanSimulateData *>(BLI_task_pool_user_data(pool));
509 const Ocean *o = osd->o;
510 const float chop_amount = osd->chop_amount;
511 int i, j;
512
513 for (i = 0; i < o->_M; i++) {
514 for (j = 0; j <= o->_N / 2; j++) {
515 fftw_complex mul_param;
516
517 // init_complex(mul_param, -scale, 0);
518 init_complex(mul_param, -1, 0);
519
520 mul_complex_f(mul_param, mul_param, chop_amount);
521 mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
522 mul_complex_f(mul_param,
523 mul_param,
524 ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ?
525 0.0f :
526 o->_kx[i] * o->_kx[i] / o->_k[i * (1 + o->_N / 2) + j]));
527 init_complex(o->_fft_in_jxx[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
528 }
529 }
530 fftw_execute(o->_Jxx_plan);
531
532 for (i = 0; i < o->_M; i++) {
533 for (j = 0; j < o->_N; j++) {
534 o->_Jxx[i * o->_N + j] += 1.0;
535 }
536 }
537}
538
539static void ocean_compute_jacobian_jzz(TaskPool *__restrict pool, void * /*taskdata*/)
540{
541 OceanSimulateData *osd = static_cast<OceanSimulateData *>(BLI_task_pool_user_data(pool));
542 const Ocean *o = osd->o;
543 const float chop_amount = osd->chop_amount;
544 int i, j;
545
546 for (i = 0; i < o->_M; i++) {
547 for (j = 0; j <= o->_N / 2; j++) {
548 fftw_complex mul_param;
549
550 // init_complex(mul_param, -scale, 0);
551 init_complex(mul_param, -1, 0);
552
553 mul_complex_f(mul_param, mul_param, chop_amount);
554 mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
555 mul_complex_f(mul_param,
556 mul_param,
557 ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ?
558 0.0f :
559 o->_kz[j] * o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j]));
560 init_complex(o->_fft_in_jzz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
561 }
562 }
563 fftw_execute(o->_Jzz_plan);
564
565 for (i = 0; i < o->_M; i++) {
566 for (j = 0; j < o->_N; j++) {
567 o->_Jzz[i * o->_N + j] += 1.0;
568 }
569 }
570}
571
572static void ocean_compute_jacobian_jxz(TaskPool *__restrict pool, void * /*taskdata*/)
573{
574 OceanSimulateData *osd = static_cast<OceanSimulateData *>(BLI_task_pool_user_data(pool));
575 const Ocean *o = osd->o;
576 const float chop_amount = osd->chop_amount;
577 int i, j;
578
579 for (i = 0; i < o->_M; i++) {
580 for (j = 0; j <= o->_N / 2; j++) {
581 fftw_complex mul_param;
582
583 // init_complex(mul_param, -scale, 0);
584 init_complex(mul_param, -1, 0);
585
586 mul_complex_f(mul_param, mul_param, chop_amount);
587 mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
588 mul_complex_f(mul_param,
589 mul_param,
590 ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ?
591 0.0f :
592 o->_kx[i] * o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j]));
593 init_complex(o->_fft_in_jxz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
594 }
595 }
596 fftw_execute(o->_Jxz_plan);
597}
598
599static void ocean_compute_normal_x(TaskPool *__restrict pool, void * /*taskdata*/)
600{
601 OceanSimulateData *osd = static_cast<OceanSimulateData *>(BLI_task_pool_user_data(pool));
602 const Ocean *o = osd->o;
603 int i, j;
604
605 for (i = 0; i < o->_M; i++) {
606 for (j = 0; j <= o->_N / 2; j++) {
607 fftw_complex mul_param;
608
609 init_complex(mul_param, 0.0, -1.0);
610 mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
611 mul_complex_f(mul_param, mul_param, o->_kx[i]);
612 init_complex(o->_fft_in_nx[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
613 }
614 }
615 fftw_execute(o->_N_x_plan);
616}
617
618static void ocean_compute_normal_z(TaskPool *__restrict pool, void * /*taskdata*/)
619{
620 OceanSimulateData *osd = static_cast<OceanSimulateData *>(BLI_task_pool_user_data(pool));
621 const Ocean *o = osd->o;
622 int i, j;
623
624 for (i = 0; i < o->_M; i++) {
625 for (j = 0; j <= o->_N / 2; j++) {
626 fftw_complex mul_param;
627
628 init_complex(mul_param, 0.0, -1.0);
629 mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
630 mul_complex_f(mul_param, mul_param, o->_kz[i]);
631 init_complex(o->_fft_in_nz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
632 }
633 }
634 fftw_execute(o->_N_z_plan);
635}
636
637bool BKE_ocean_is_valid(const Ocean *o)
638{
639 return o->_k != nullptr;
640}
641
642void BKE_ocean_simulate(Ocean *o, float t, float scale, float chop_amount)
643{
644 TaskPool *pool;
645
646 OceanSimulateData osd;
647
648 scale *= o->normalize_factor;
649
650 osd.o = o;
651 osd.t = t;
652 osd.scale = scale;
653 osd.chop_amount = chop_amount;
654
656
657 BLI_rw_mutex_lock(&o->oceanmutex, THREAD_LOCK_WRITE);
658
659 /* Note about multi-threading here: we have to run a first set of computations (htilda one)
660 * before we can run all others, since they all depend on it.
661 * So we make a first parallelized forloop run for htilda,
662 * and then pack all other computations into a set of parallel tasks.
663 * This is not optimal in all cases,
664 * but remains reasonably simple and should be OK most of the time. */
665
666 /* compute a new htilda */
667 TaskParallelSettings settings;
669 settings.use_threading = (o->_M > 16);
670 BLI_task_parallel_range(0, o->_M, &osd, ocean_compute_htilda, &settings);
671
672 if (o->_do_disp_y) {
673 BLI_task_pool_push(pool, ocean_compute_displacement_y, nullptr, false, nullptr);
674 }
675
676 if (o->_do_chop) {
677 BLI_task_pool_push(pool, ocean_compute_displacement_x, nullptr, false, nullptr);
678 BLI_task_pool_push(pool, ocean_compute_displacement_z, nullptr, false, nullptr);
679 }
680
681 if (o->_do_jacobian) {
682 BLI_task_pool_push(pool, ocean_compute_jacobian_jxx, nullptr, false, nullptr);
683 BLI_task_pool_push(pool, ocean_compute_jacobian_jzz, nullptr, false, nullptr);
684 BLI_task_pool_push(pool, ocean_compute_jacobian_jxz, nullptr, false, nullptr);
685 }
686
687 if (o->_do_normals) {
688 BLI_task_pool_push(pool, ocean_compute_normal_x, nullptr, false, nullptr);
689 BLI_task_pool_push(pool, ocean_compute_normal_z, nullptr, false, nullptr);
690 o->_N_y = 1.0f / scale;
691 }
692
694
695 BLI_rw_mutex_unlock(&o->oceanmutex);
696
697 BLI_task_pool_free(pool);
698}
699
700static void set_height_normalize_factor(Ocean *oc)
701{
702 float res = 1.0;
703 float max_h = 0.0;
704
705 int i, j;
706
707 if (!oc->_do_disp_y) {
708 return;
709 }
710
711 oc->normalize_factor = 1.0;
712
713 BKE_ocean_simulate(oc, 0.0, 1.0, 0);
714
715 BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ);
716
717 for (i = 0; i < oc->_M; i++) {
718 for (j = 0; j < oc->_N; j++) {
719 max_h = std::max<double>(max_h, fabs(oc->_disp_y[i * oc->_N + j]));
720 }
721 }
722
723 BLI_rw_mutex_unlock(&oc->oceanmutex);
724
725 if (max_h == 0.0f) {
726 max_h = 0.00001f; /* just in case ... */
727 }
728
729 res = 1.0f / (max_h);
730
731 oc->normalize_factor = res;
732}
733
735{
736 Ocean *oc = MEM_callocN<Ocean>("ocean sim data");
737
738 BLI_rw_mutex_init(&oc->oceanmutex);
739
740 return oc;
741}
742
743bool BKE_ocean_ensure(OceanModifierData *omd, const int resolution)
744{
745 if (omd->ocean) {
746 /* Check that the ocean has the same resolution than we want now. */
747 if (omd->ocean->_M == resolution * resolution) {
748 return false;
749 }
750
751 BKE_ocean_free(omd->ocean);
752 }
753
754 omd->ocean = BKE_ocean_add();
755 BKE_ocean_init_from_modifier(omd->ocean, omd, resolution);
756 return true;
757}
758
759bool BKE_ocean_init_from_modifier(Ocean *ocean, OceanModifierData const *omd, const int resolution)
760{
761 short do_heightfield, do_chop, do_normals, do_jacobian, do_spray;
762
763 do_heightfield = true;
764 do_chop = (omd->chop_amount > 0);
765 do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS);
766 do_jacobian = (omd->flag & MOD_OCEAN_GENERATE_FOAM);
767 do_spray = do_jacobian && (omd->flag & MOD_OCEAN_GENERATE_SPRAY);
768
769 BKE_ocean_free_data(ocean);
770
771 return BKE_ocean_init(ocean,
772 resolution * resolution,
773 resolution * resolution,
774 omd->spatial_size,
775 omd->spatial_size,
776 omd->wind_velocity,
777 omd->smallest_wave,
778 1.0,
779 omd->wave_direction,
780 omd->damp,
781 omd->wave_alignment,
782 omd->depth,
783 omd->time,
784 omd->spectrum,
785 omd->fetch_jonswap,
787 do_heightfield,
788 do_chop,
789 do_spray,
790 do_normals,
791 do_jacobian,
792 omd->seed);
793}
794
795bool BKE_ocean_init(Ocean *o,
796 int M,
797 int N,
798 float Lx,
799 float Lz,
800 float V,
801 float l,
802 float A,
803 float w,
804 float damp,
805 float alignment,
806 float depth,
807 float time,
808 int spectrum,
809 float fetch_jonswap,
810 float sharpen_peak_jonswap,
811 short do_height_field,
812 short do_chop,
813 short do_spray,
814 short do_normals,
815 short do_jacobian,
816 int seed)
817{
818 int i, j, ii;
819
820 BLI_rw_mutex_lock(&o->oceanmutex, THREAD_LOCK_WRITE);
821
822 o->_M = M;
823 o->_N = N;
824 o->_V = V;
825 o->_l = l;
826 o->_A = A;
827 o->_w = w;
828 o->_damp_reflections = 1.0f - damp;
829 o->_wind_alignment = alignment * 10.0f;
830 o->_depth = depth;
831 o->_Lx = Lx;
832 o->_Lz = Lz;
833 o->_wx = cos(w);
834 o->_wz = -sin(w); /* wave direction */
835 o->_L = V * V / GRAVITY; /* largest wave for a given velocity V */
836 o->time = time;
837
838 /* Spectrum to use. */
839 o->_spectrum = spectrum;
840
841 /* Common JONSWAP parameters. */
842 o->_fetch_jonswap = fetch_jonswap;
843 o->_sharpen_peak_jonswap = sharpen_peak_jonswap * 10.0f;
844
845 /* NOTE: most modifiers don't account for failure to allocate.
846 * In this case however a large resolution can easily perform large allocations that fail,
847 * support early exiting in this case. */
848 if ((o->_k = MEM_malloc_arrayN<float>(size_t(M) * (1 + size_t(N) / 2), "ocean_k")) &&
849 (o->_h0 = MEM_malloc_arrayN<fftw_complex>(size_t(M) * size_t(N), "ocean_h0")) &&
850 (o->_h0_minus = MEM_malloc_arrayN<fftw_complex>(size_t(M) * size_t(N), "ocean_h0_minus")) &&
851 (o->_kx = MEM_malloc_arrayN<float>(size_t(o->_M), "ocean_kx")) &&
852 (o->_kz = MEM_malloc_arrayN<float>(size_t(o->_N), "ocean_kz")))
853 {
854 /* Success. */
855 }
856 else {
857 MEM_SAFE_FREE(o->_k);
858 MEM_SAFE_FREE(o->_h0);
859 MEM_SAFE_FREE(o->_h0_minus);
860 MEM_SAFE_FREE(o->_kx);
861 MEM_SAFE_FREE(o->_kz);
862
863 BLI_rw_mutex_unlock(&o->oceanmutex);
864 return false;
865 }
866
867 o->_do_disp_y = do_height_field;
868 o->_do_normals = do_normals;
869 o->_do_spray = do_spray;
870 o->_do_chop = do_chop;
871 o->_do_jacobian = do_jacobian;
872
873 /* make this robust in the face of erroneous usage */
874 if (o->_Lx == 0.0f) {
875 o->_Lx = 0.001f;
876 }
877
878 if (o->_Lz == 0.0f) {
879 o->_Lz = 0.001f;
880 }
881
882 /* The +VE components and DC. */
883 for (i = 0; i <= o->_M / 2; i++) {
884 o->_kx[i] = 2.0f * float(M_PI) * i / o->_Lx;
885 }
886
887 /* The -VE components. */
888 for (i = o->_M - 1, ii = 0; i > o->_M / 2; i--, ii++) {
889 o->_kx[i] = -2.0f * float(M_PI) * ii / o->_Lx;
890 }
891
892 /* The +VE components and DC. */
893 for (i = 0; i <= o->_N / 2; i++) {
894 o->_kz[i] = 2.0f * float(M_PI) * i / o->_Lz;
895 }
896
897 /* The -VE components. */
898 for (i = o->_N - 1, ii = 0; i > o->_N / 2; i--, ii++) {
899 o->_kz[i] = -2.0f * float(M_PI) * ii / o->_Lz;
900 }
901
902 /* pre-calculate the k matrix */
903 for (i = 0; i < o->_M; i++) {
904 for (j = 0; j <= o->_N / 2; j++) {
905 o->_k[size_t(i) * (1 + o->_N / 2) + j] = sqrt(o->_kx[i] * o->_kx[i] + o->_kz[j] * o->_kz[j]);
906 }
907 }
908
909 RNG *rng = BLI_rng_new(seed);
910
911 for (i = 0; i < o->_M; i++) {
912 for (j = 0; j < o->_N; j++) {
913 /* This ensures we get a value tied to the surface location, avoiding dramatic surface
914 * change with changing resolution.
915 * Explicitly cast to signed int first to ensure consistent behavior on all processors,
916 * since behavior of `float` to `uint` cast is undefined in C. */
917 const int hash_x = o->_kx[i] * 360.0f;
918 const int hash_z = o->_kz[j] * 360.0f;
919 int new_seed = seed + BLI_hash_int_2d(hash_x, hash_z);
920
921 BLI_rng_seed(rng, new_seed);
922 float r1 = gaussRand(rng);
923 float r2 = gaussRand(rng);
924
925 fftw_complex r1r2;
926 init_complex(r1r2, r1, r2);
927 switch (o->_spectrum) {
929 mul_complex_f(o->_h0[i * o->_N + j],
930 r1r2,
931 sqrt(BLI_ocean_spectrum_jonswap(o, o->_kx[i], o->_kz[j]) / 2.0f));
932 mul_complex_f(o->_h0_minus[i * o->_N + j],
933 r1r2,
934 sqrt(BLI_ocean_spectrum_jonswap(o, -o->_kx[i], -o->_kz[j]) / 2.0f));
935 break;
937 mul_complex_f(
938 o->_h0[i * o->_N + j],
939 r1r2,
940 sqrt(BLI_ocean_spectrum_texelmarsenarsloe(o, o->_kx[i], o->_kz[j]) / 2.0f));
941 mul_complex_f(
942 o->_h0_minus[i * o->_N + j],
943 r1r2,
944 sqrt(BLI_ocean_spectrum_texelmarsenarsloe(o, -o->_kx[i], -o->_kz[j]) / 2.0f));
945 break;
947 mul_complex_f(o->_h0[i * o->_N + j],
948 r1r2,
949 sqrt(BLI_ocean_spectrum_piersonmoskowitz(o, o->_kx[i], o->_kz[j]) / 2.0f));
950 mul_complex_f(
951 o->_h0_minus[i * o->_N + j],
952 r1r2,
953 sqrt(BLI_ocean_spectrum_piersonmoskowitz(o, -o->_kx[i], -o->_kz[j]) / 2.0f));
954 break;
955 default:
956 mul_complex_f(o->_h0[i * o->_N + j], r1r2, sqrt(Ph(o, o->_kx[i], o->_kz[j]) / 2.0f));
957 mul_complex_f(
958 o->_h0_minus[i * o->_N + j], r1r2, sqrt(Ph(o, -o->_kx[i], -o->_kz[j]) / 2.0f));
959 break;
960 }
961 }
962 }
963
964 o->_fft_in = MEM_malloc_arrayN<fftw_complex>(size_t(o->_M) * (1 + size_t(o->_N) / 2),
965 "ocean_fft_in");
966 o->_htilda = MEM_malloc_arrayN<fftw_complex>(size_t(o->_M) * (1 + size_t(o->_N) / 2),
967 "ocean_htilda");
968
970
971 if (o->_do_disp_y) {
972 o->_disp_y = MEM_malloc_arrayN<double>(size_t(o->_M) * size_t(o->_N), "ocean_disp_y");
973 o->_disp_y_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in, o->_disp_y, FFTW_ESTIMATE);
974 }
975
976 if (o->_do_normals) {
977 o->_fft_in_nx = MEM_malloc_arrayN<fftw_complex>(size_t(o->_M) * (1 + size_t(o->_N) / 2),
978 "ocean_fft_in_nx");
979 o->_fft_in_nz = MEM_malloc_arrayN<fftw_complex>(size_t(o->_M) * (1 + size_t(o->_N) / 2),
980 "ocean_fft_in_nz");
981
982 o->_N_x = MEM_malloc_arrayN<double>(size_t(o->_M) * size_t(o->_N), "ocean_N_x");
983 // o->_N_y = (float *) fftwf_malloc(o->_M * o->_N * sizeof(float)); /* (MEM01) */
984 o->_N_z = MEM_malloc_arrayN<double>(size_t(o->_M) * size_t(o->_N), "ocean_N_z");
985
986 o->_N_x_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_nx, o->_N_x, FFTW_ESTIMATE);
987 o->_N_z_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_nz, o->_N_z, FFTW_ESTIMATE);
988 }
989
990 if (o->_do_chop) {
991 o->_fft_in_x = MEM_malloc_arrayN<fftw_complex>(size_t(o->_M) * (1 + size_t(o->_N) / 2),
992 "ocean_fft_in_x");
993 o->_fft_in_z = MEM_malloc_arrayN<fftw_complex>(size_t(o->_M) * (1 + size_t(o->_N) / 2),
994 "ocean_fft_in_z");
995
996 o->_disp_x = MEM_malloc_arrayN<double>(size_t(o->_M) * size_t(o->_N), "ocean_disp_x");
997 o->_disp_z = MEM_malloc_arrayN<double>(size_t(o->_M) * size_t(o->_N), "ocean_disp_z");
998
999 o->_disp_x_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_x, o->_disp_x, FFTW_ESTIMATE);
1000 o->_disp_z_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_z, o->_disp_z, FFTW_ESTIMATE);
1001 }
1002 if (o->_do_jacobian) {
1003 o->_fft_in_jxx = MEM_malloc_arrayN<fftw_complex>(size_t(o->_M) * (1 + size_t(o->_N) / 2),
1004 "ocean_fft_in_jxx");
1005 o->_fft_in_jzz = MEM_malloc_arrayN<fftw_complex>(size_t(o->_M) * (1 + size_t(o->_N) / 2),
1006 "ocean_fft_in_jzz");
1007 o->_fft_in_jxz = MEM_malloc_arrayN<fftw_complex>(size_t(o->_M) * (1 + size_t(o->_N) / 2),
1008 "ocean_fft_in_jxz");
1009
1010 o->_Jxx = MEM_malloc_arrayN<double>(size_t(o->_M) * size_t(o->_N), "ocean_Jxx");
1011 o->_Jzz = MEM_malloc_arrayN<double>(size_t(o->_M) * size_t(o->_N), "ocean_Jzz");
1012 o->_Jxz = MEM_malloc_arrayN<double>(size_t(o->_M) * size_t(o->_N), "ocean_Jxz");
1013
1014 o->_Jxx_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_jxx, o->_Jxx, FFTW_ESTIMATE);
1015 o->_Jzz_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_jzz, o->_Jzz, FFTW_ESTIMATE);
1016 o->_Jxz_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_jxz, o->_Jxz, FFTW_ESTIMATE);
1017 }
1018
1020
1021 BLI_rw_mutex_unlock(&o->oceanmutex);
1022
1023 set_height_normalize_factor(o);
1024
1025 BLI_rng_free(rng);
1026
1027 return true;
1028}
1029
1030void BKE_ocean_free_data(Ocean *oc)
1031{
1032 if (!oc) {
1033 return;
1034 }
1035
1036 BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_WRITE);
1037
1039
1040 if (oc->_do_disp_y) {
1041 fftw_destroy_plan(oc->_disp_y_plan);
1042 MEM_freeN(oc->_disp_y);
1043 }
1044
1045 if (oc->_do_normals) {
1046 MEM_freeN(oc->_fft_in_nx);
1047 MEM_freeN(oc->_fft_in_nz);
1048 fftw_destroy_plan(oc->_N_x_plan);
1049 fftw_destroy_plan(oc->_N_z_plan);
1050 MEM_freeN(oc->_N_x);
1051 // fftwf_free(oc->_N_y); /* (MEM01) */
1052 MEM_freeN(oc->_N_z);
1053 }
1054
1055 if (oc->_do_chop) {
1056 MEM_freeN(oc->_fft_in_x);
1057 MEM_freeN(oc->_fft_in_z);
1058 fftw_destroy_plan(oc->_disp_x_plan);
1059 fftw_destroy_plan(oc->_disp_z_plan);
1060 MEM_freeN(oc->_disp_x);
1061 MEM_freeN(oc->_disp_z);
1062 }
1063
1064 if (oc->_do_jacobian) {
1065 MEM_freeN(oc->_fft_in_jxx);
1066 MEM_freeN(oc->_fft_in_jzz);
1067 MEM_freeN(oc->_fft_in_jxz);
1068 fftw_destroy_plan(oc->_Jxx_plan);
1069 fftw_destroy_plan(oc->_Jzz_plan);
1070 fftw_destroy_plan(oc->_Jxz_plan);
1071 MEM_freeN(oc->_Jxx);
1072 MEM_freeN(oc->_Jzz);
1073 MEM_freeN(oc->_Jxz);
1074 }
1075
1077
1078 if (oc->_fft_in) {
1079 MEM_freeN(oc->_fft_in);
1080 }
1081
1082 /* check that ocean data has been initialized */
1083 if (oc->_htilda) {
1084 MEM_freeN(oc->_htilda);
1085 MEM_freeN(oc->_k);
1086 MEM_freeN(oc->_h0);
1087 MEM_freeN(oc->_h0_minus);
1088 MEM_freeN(oc->_kx);
1089 MEM_freeN(oc->_kz);
1090 }
1091
1092 BLI_rw_mutex_unlock(&oc->oceanmutex);
1093}
1094
1095void BKE_ocean_free(Ocean *oc)
1096{
1097 if (!oc) {
1098 return;
1099 }
1100
1102 BLI_rw_mutex_end(&oc->oceanmutex);
1103
1104 MEM_freeN(oc);
1105}
1106
1107# undef GRAVITY
1108
1109/* ********* Baking/Caching ********* */
1110
1111# define CACHE_TYPE_DISPLACE 1
1112# define CACHE_TYPE_FOAM 2
1113# define CACHE_TYPE_NORMAL 3
1114# define CACHE_TYPE_SPRAY 4
1115# define CACHE_TYPE_SPRAY_INVERSE 5
1116
1117static void cache_filepath(
1118 char *filepath, const char *dirname, const char *relbase, int frame, int type)
1119{
1120 char cachepath[FILE_MAX];
1121 const char *filename;
1122
1123 switch (type) {
1124 case CACHE_TYPE_FOAM:
1125 filename = "foam_";
1126 break;
1127 case CACHE_TYPE_NORMAL:
1128 filename = "normal_";
1129 break;
1130 case CACHE_TYPE_SPRAY:
1131 filename = "spray_";
1132 break;
1133 case CACHE_TYPE_SPRAY_INVERSE:
1134 filename = "spray_inverse_";
1135 break;
1136 case CACHE_TYPE_DISPLACE:
1137 default:
1138 filename = "disp_";
1139 break;
1140 }
1141
1142 BLI_path_join(cachepath, sizeof(cachepath), dirname, filename);
1143
1145 filepath, cachepath, relbase, nullptr, frame, R_IMF_IMTYPE_OPENEXR, true, true, "");
1146 BLI_assert_msg(errors.is_empty(),
1147 "Path parsing errors should only occur when a variable map is provided.");
1148 UNUSED_VARS_NDEBUG(errors);
1149}
1150
1151/* silly functions but useful to inline when the args do a lot of indirections */
1152MINLINE void rgb_to_rgba_unit_alpha(float r_rgba[4], const float rgb[3])
1153{
1154 r_rgba[0] = rgb[0];
1155 r_rgba[1] = rgb[1];
1156 r_rgba[2] = rgb[2];
1157 r_rgba[3] = 1.0f;
1158}
1159MINLINE void value_to_rgba_unit_alpha(float r_rgba[4], const float value)
1160{
1161 r_rgba[0] = value;
1162 r_rgba[1] = value;
1163 r_rgba[2] = value;
1164 r_rgba[3] = 1.0f;
1165}
1166
1168{
1169 int i, f = 0;
1170
1171 if (!och) {
1172 return;
1173 }
1174
1175 if (och->ibufs_disp) {
1176 for (i = och->start, f = 0; i <= och->end; i++, f++) {
1177 if (och->ibufs_disp[f]) {
1178 IMB_freeImBuf(och->ibufs_disp[f]);
1179 }
1180 }
1181 MEM_freeN(och->ibufs_disp);
1182 }
1183
1184 if (och->ibufs_foam) {
1185 for (i = och->start, f = 0; i <= och->end; i++, f++) {
1186 if (och->ibufs_foam[f]) {
1187 IMB_freeImBuf(och->ibufs_foam[f]);
1188 }
1189 }
1190 MEM_freeN(och->ibufs_foam);
1191 }
1192
1193 if (och->ibufs_spray) {
1194 for (i = och->start, f = 0; i <= och->end; i++, f++) {
1195 if (och->ibufs_spray[f]) {
1196 IMB_freeImBuf(och->ibufs_spray[f]);
1197 }
1198 }
1199 MEM_freeN(och->ibufs_spray);
1200 }
1201
1202 if (och->ibufs_spray_inverse) {
1203 for (i = och->start, f = 0; i <= och->end; i++, f++) {
1204 if (och->ibufs_spray_inverse[f]) {
1206 }
1207 }
1209 }
1210
1211 if (och->ibufs_norm) {
1212 for (i = och->start, f = 0; i <= och->end; i++, f++) {
1213 if (och->ibufs_norm[f]) {
1214 IMB_freeImBuf(och->ibufs_norm[f]);
1215 }
1216 }
1217 MEM_freeN(och->ibufs_norm);
1218 }
1219
1220 if (och->time) {
1221 MEM_freeN(och->time);
1222 }
1223 MEM_freeN(och);
1224}
1225
1226void BKE_ocean_cache_eval_uv(OceanCache *och, OceanResult *ocr, int f, float u, float v)
1227{
1228 int res_x = och->resolution_x;
1229 int res_y = och->resolution_y;
1230 float result[4];
1231
1232 u = fmod(u, 1.0);
1233 v = fmod(v, 1.0);
1234
1235 if (u < 0) {
1236 u += 1.0f;
1237 }
1238 if (v < 0) {
1239 v += 1.0f;
1240 }
1241
1242 if (och->ibufs_disp[f]) {
1243 ibuf_sample(och->ibufs_disp[f], u, v, (1.0f / float(res_x)), (1.0f / float(res_y)), result);
1244 copy_v3_v3(ocr->disp, result);
1245 }
1246
1247 if (och->ibufs_foam[f]) {
1248 ibuf_sample(och->ibufs_foam[f], u, v, (1.0f / float(res_x)), (1.0f / float(res_y)), result);
1249 ocr->foam = result[0];
1250 }
1251
1252 if (och->ibufs_spray[f]) {
1253 ibuf_sample(och->ibufs_spray[f], u, v, (1.0f / float(res_x)), (1.0f / float(res_y)), result);
1254 copy_v3_v3(ocr->Eplus, result);
1255 }
1256
1257 if (och->ibufs_spray_inverse[f]) {
1259 och->ibufs_spray_inverse[f], u, v, (1.0f / float(res_x)), (1.0f / float(res_y)), result);
1260 copy_v3_v3(ocr->Eminus, result);
1261 }
1262
1263 if (och->ibufs_norm[f]) {
1264 ibuf_sample(och->ibufs_norm[f], u, v, (1.0f / float(res_x)), (1.0f / float(res_y)), result);
1265 copy_v3_v3(ocr->normal, result);
1266 }
1267}
1268
1269void BKE_ocean_cache_eval_ij(OceanCache *och, OceanResult *ocr, int f, int i, int j)
1270{
1271 const int res_x = och->resolution_x;
1272 const int res_y = och->resolution_y;
1273
1274 if (i < 0) {
1275 i = -i;
1276 }
1277 if (j < 0) {
1278 j = -j;
1279 }
1280
1281 i = i % res_x;
1282 j = j % res_y;
1283
1284 if (och->ibufs_disp[f]) {
1285 copy_v3_v3(ocr->disp, &och->ibufs_disp[f]->float_buffer.data[4 * (res_x * j + i)]);
1286 }
1287
1288 if (och->ibufs_foam[f]) {
1289 ocr->foam = och->ibufs_foam[f]->float_buffer.data[4 * (res_x * j + i)];
1290 }
1291
1292 if (och->ibufs_spray[f]) {
1293 copy_v3_v3(ocr->Eplus, &och->ibufs_spray[f]->float_buffer.data[4 * (res_x * j + i)]);
1294 }
1295
1296 if (och->ibufs_spray_inverse[f]) {
1297 copy_v3_v3(ocr->Eminus, &och->ibufs_spray_inverse[f]->float_buffer.data[4 * (res_x * j + i)]);
1298 }
1299
1300 if (och->ibufs_norm[f]) {
1301 copy_v3_v3(ocr->normal, &och->ibufs_norm[f]->float_buffer.data[4 * (res_x * j + i)]);
1302 }
1303}
1304
1305OceanCache *BKE_ocean_init_cache(const char *bakepath,
1306 const char *relbase,
1307 int start,
1308 int end,
1309 float wave_scale,
1310 float chop_amount,
1311 float foam_coverage,
1312 float foam_fade,
1313 int resolution)
1314{
1315 OceanCache *och = MEM_callocN<OceanCache>("ocean cache data");
1316
1317 och->bakepath = bakepath;
1318 och->relbase = relbase;
1319
1320 och->start = start;
1321 och->end = end;
1322 och->duration = (end - start) + 1;
1323 och->wave_scale = wave_scale;
1324 och->chop_amount = chop_amount;
1325 och->foam_coverage = foam_coverage;
1326 och->foam_fade = foam_fade;
1327 och->resolution_x = resolution * resolution;
1328 och->resolution_y = resolution * resolution;
1329
1330 och->ibufs_disp = MEM_calloc_arrayN<ImBuf *>(och->duration, "displacement imbuf pointer array");
1331 och->ibufs_foam = MEM_calloc_arrayN<ImBuf *>(och->duration, "foam imbuf pointer array");
1332 och->ibufs_spray = MEM_calloc_arrayN<ImBuf *>(och->duration, "spray imbuf pointer array");
1334 "spray_inverse imbuf pointer array");
1335 och->ibufs_norm = MEM_calloc_arrayN<ImBuf *>(och->duration, "normal imbuf pointer array");
1336
1337 och->time = nullptr;
1338
1339 return och;
1340}
1341
1342void BKE_ocean_simulate_cache(OceanCache *och, int frame)
1343{
1344 char filepath[FILE_MAX];
1345
1346 /* ibufs array is zero based, but filenames are based on frame numbers */
1347 /* still need to clamp frame numbers to valid range of images on disk though */
1348 CLAMP(frame, och->start, och->end);
1349 const int f = frame - och->start; /* shift to 0 based */
1350
1351 /* if image is already loaded in mem, return */
1352 if (och->ibufs_disp[f] != nullptr) {
1353 return;
1354 }
1355
1356 /* Use default color spaces since we know for sure cache
1357 * files were saved with default settings too. */
1358
1359 cache_filepath(filepath, och->bakepath, och->relbase, frame, CACHE_TYPE_DISPLACE);
1360 och->ibufs_disp[f] = IMB_load_image_from_filepath(filepath, 0);
1361
1362 cache_filepath(filepath, och->bakepath, och->relbase, frame, CACHE_TYPE_FOAM);
1363 och->ibufs_foam[f] = IMB_load_image_from_filepath(filepath, 0);
1364
1365 cache_filepath(filepath, och->bakepath, och->relbase, frame, CACHE_TYPE_SPRAY);
1366 och->ibufs_spray[f] = IMB_load_image_from_filepath(filepath, 0);
1367
1368 cache_filepath(filepath, och->bakepath, och->relbase, frame, CACHE_TYPE_SPRAY_INVERSE);
1370
1371 cache_filepath(filepath, och->bakepath, och->relbase, frame, CACHE_TYPE_NORMAL);
1372 och->ibufs_norm[f] = IMB_load_image_from_filepath(filepath, 0);
1373}
1374
1375void BKE_ocean_bake(Ocean *o,
1376 OceanCache *och,
1377 void (*update_cb)(void *, float progress, int *cancel),
1378 void *update_cb_data)
1379{
1380 /* NOTE(@ideasman42): some of these values remain uninitialized unless certain options
1381 * are enabled, take care that #BKE_ocean_eval_ij() initializes a member before use. */
1382 OceanResult ocr;
1383
1384 ImageFormatData imf = {0};
1385
1386 int f, i = 0, x, y, cancel = 0;
1387 float progress;
1388
1389 ImBuf *ibuf_foam, *ibuf_disp, *ibuf_normal, *ibuf_spray, *ibuf_spray_inverse;
1390 float *prev_foam;
1391 int res_x = och->resolution_x;
1392 int res_y = och->resolution_y;
1393 char filepath[FILE_MAX];
1394 // RNG *rng;
1395
1396 if (!o) {
1397 return;
1398 }
1399
1400 if (o->_do_jacobian) {
1401 prev_foam = MEM_calloc_arrayN<float>(size_t(res_x) * size_t(res_y),
1402 "previous frame foam bake data");
1403 }
1404 else {
1405 prev_foam = nullptr;
1406 }
1407
1408 // rng = BLI_rng_new(0);
1409
1410 /* setup image format */
1414
1415 for (f = och->start, i = 0; f <= och->end; f++, i++) {
1416
1417 /* create a new imbuf to store image for this frame */
1418 ibuf_foam = IMB_allocImBuf(res_x, res_y, 32, IB_float_data);
1419 ibuf_disp = IMB_allocImBuf(res_x, res_y, 32, IB_float_data);
1420 ibuf_normal = IMB_allocImBuf(res_x, res_y, 32, IB_float_data);
1421 ibuf_spray = IMB_allocImBuf(res_x, res_y, 32, IB_float_data);
1422 ibuf_spray_inverse = IMB_allocImBuf(res_x, res_y, 32, IB_float_data);
1423
1424 BKE_ocean_simulate(o, och->time[i], och->wave_scale, och->chop_amount);
1425
1426 /* add new foam */
1427 for (y = 0; y < res_y; y++) {
1428 for (x = 0; x < res_x; x++) {
1429
1430 BKE_ocean_eval_ij(o, &ocr, x, y);
1431
1432 /* add to the image */
1433 rgb_to_rgba_unit_alpha(&ibuf_disp->float_buffer.data[4 * (res_x * y + x)], ocr.disp);
1434
1435 if (o->_do_jacobian) {
1436 /* TODO(@ideasman42): cleanup unused code. */
1437
1438 float /* r, */ /* UNUSED */ pr = 0.0f, foam_result;
1439 float neg_disp, neg_eplus;
1440
1442
1443 /* accumulate previous value for this cell */
1444 if (i > 0) {
1445 pr = prev_foam[res_x * y + x];
1446 }
1447
1448 // r = BLI_rng_get_float(rng); /* UNUSED */ /* randomly reduce foam */
1449
1450 // pr = pr * och->foam_fade; /* overall fade */
1451
1452 /* Remember ocean coord system is Y up!
1453 * break up the foam where height (Y) is low (wave valley),
1454 * and X and Z displacement is greatest. */
1455
1456 neg_disp = ocr.disp[1] < 0.0f ? 1.0f + ocr.disp[1] : 1.0f;
1457 neg_disp = neg_disp < 0.0f ? 0.0f : neg_disp;
1458
1459 /* foam, 'ocr.Eplus' only initialized with do_jacobian */
1460 neg_eplus = ocr.Eplus[2] < 0.0f ? 1.0f + ocr.Eplus[2] : 1.0f;
1461 neg_eplus = neg_eplus < 0.0f ? 0.0f : neg_eplus;
1462
1463 if (pr < 1.0f) {
1464 pr *= pr;
1465 }
1466
1467 pr *= och->foam_fade * (0.75f + neg_eplus * 0.25f);
1468
1469 /* A full clamping should not be needed! */
1470 foam_result = min_ff(pr + ocr.foam, 1.0f);
1471
1472 prev_foam[res_x * y + x] = foam_result;
1473
1474 // foam_result = min_ff(foam_result, 1.0f);
1475
1476 value_to_rgba_unit_alpha(&ibuf_foam->float_buffer.data[4 * (res_x * y + x)],
1477 foam_result);
1478
1479 /* spray map baking */
1480 if (o->_do_spray) {
1481 rgb_to_rgba_unit_alpha(&ibuf_spray->float_buffer.data[4 * (res_x * y + x)], ocr.Eplus);
1482 rgb_to_rgba_unit_alpha(&ibuf_spray_inverse->float_buffer.data[4 * (res_x * y + x)],
1483 ocr.Eminus);
1484 }
1485 }
1486
1487 if (o->_do_normals) {
1488 rgb_to_rgba_unit_alpha(&ibuf_normal->float_buffer.data[4 * (res_x * y + x)], ocr.normal);
1489 }
1490 }
1491 }
1492
1493 /* write the images */
1494 cache_filepath(filepath, och->bakepath, och->relbase, f, CACHE_TYPE_DISPLACE);
1495 if (false == BKE_imbuf_write(ibuf_disp, filepath, &imf)) {
1496 printf("Cannot save Displacement File Output to %s\n", filepath);
1497 }
1498
1499 if (o->_do_jacobian) {
1500 cache_filepath(filepath, och->bakepath, och->relbase, f, CACHE_TYPE_FOAM);
1501 if (false == BKE_imbuf_write(ibuf_foam, filepath, &imf)) {
1502 printf("Cannot save Foam File Output to %s\n", filepath);
1503 }
1504
1505 if (o->_do_spray) {
1506 cache_filepath(filepath, och->bakepath, och->relbase, f, CACHE_TYPE_SPRAY);
1507 if (false == BKE_imbuf_write(ibuf_spray, filepath, &imf)) {
1508 printf("Cannot save Spray File Output to %s\n", filepath);
1509 }
1510
1511 cache_filepath(filepath, och->bakepath, och->relbase, f, CACHE_TYPE_SPRAY_INVERSE);
1512 if (false == BKE_imbuf_write(ibuf_spray_inverse, filepath, &imf)) {
1513 printf("Cannot save Spray Inverse File Output to %s\n", filepath);
1514 }
1515 }
1516 }
1517
1518 if (o->_do_normals) {
1519 cache_filepath(filepath, och->bakepath, och->relbase, f, CACHE_TYPE_NORMAL);
1520 if (false == BKE_imbuf_write(ibuf_normal, filepath, &imf)) {
1521 printf("Cannot save Normal File Output to %s\n", filepath);
1522 }
1523 }
1524
1525 IMB_freeImBuf(ibuf_disp);
1526 IMB_freeImBuf(ibuf_foam);
1527 IMB_freeImBuf(ibuf_normal);
1528 IMB_freeImBuf(ibuf_spray);
1529 IMB_freeImBuf(ibuf_spray_inverse);
1530
1531 progress = (f - och->start) / float(och->duration);
1532
1533 update_cb(update_cb_data, progress, &cancel);
1534
1535 if (cancel) {
1536 if (prev_foam) {
1537 MEM_freeN(prev_foam);
1538 }
1539 // BLI_rng_free(rng);
1540 return;
1541 }
1542 }
1543
1544 // BLI_rng_free(rng);
1545 if (prev_foam) {
1546 MEM_freeN(prev_foam);
1547 }
1548 och->baked = 1;
1549}
1550
1551#else /* WITH_OCEANSIM */
1552
1553float BKE_ocean_jminus_to_foam(float /*jminus*/, float /*coverage*/)
1554{
1555 return 0.0f;
1556}
1557
1558void BKE_ocean_eval_uv(Ocean * /*oc*/, OceanResult * /*ocr*/, float /*u*/, float /*v*/) {}
1559
1560/* use catmullrom interpolation rather than linear */
1561void BKE_ocean_eval_uv_catrom(Ocean * /*oc*/, OceanResult * /*ocr*/, float /*u*/, float /*v*/) {}
1562
1563void BKE_ocean_eval_xz(Ocean * /*oc*/, OceanResult * /*ocr*/, float /*x*/, float /*z*/) {}
1564
1565void BKE_ocean_eval_xz_catrom(Ocean * /*oc*/, OceanResult * /*ocr*/, float /*x*/, float /*z*/) {}
1566
1567void BKE_ocean_eval_ij(Ocean * /*oc*/, OceanResult * /*ocr*/, int /*i*/, int /*j*/) {}
1568
1569void BKE_ocean_simulate(Ocean * /*o*/, float /*t*/, float /*scale*/, float /*chop_amount*/) {}
1570
1572{
1573 Ocean *oc = MEM_callocN<Ocean>("ocean sim data");
1574
1575 return oc;
1576}
1577
1579 int /*M*/,
1580 int /*N*/,
1581 float /*Lx*/,
1582 float /*Lz*/,
1583 float /*V*/,
1584 float /*l*/,
1585 float /*A*/,
1586 float /*w*/,
1587 float /*damp*/,
1588 float /*alignment*/,
1589 float /*depth*/,
1590 float /*time*/,
1591 int /*spectrum*/,
1592 float /*fetch_jonswap*/,
1593 float /*sharpen_peak_jonswap*/,
1594 short /*do_height_field*/,
1595 short /*do_chop*/,
1596 short /*do_spray*/,
1597 short /*do_normals*/,
1598 short /*do_jacobian*/,
1599 int /*seed*/)
1600{
1601 return false;
1602}
1603
1605
1607{
1608 if (!oc) {
1609 return;
1610 }
1611 MEM_freeN(oc);
1612}
1613
1614/* ********* Baking/Caching ********* */
1615
1617{
1618 if (!och) {
1619 return;
1620 }
1621
1622 MEM_freeN(och);
1623}
1624
1626 OceanCache * /*och*/, OceanResult * /*ocr*/, int /*f*/, float /*u*/, float /*v*/)
1627{
1628}
1629
1631 OceanCache * /*och*/, OceanResult * /*ocr*/, int /*f*/, int /*i*/, int /*j*/)
1632{
1633}
1634
1635OceanCache *BKE_ocean_init_cache(const char * /*bakepath*/,
1636 const char * /*relbase*/,
1637 int /*start*/,
1638 int /*end*/,
1639 float /*wave_scale*/,
1640 float /*chop_amount*/,
1641 float /*foam_coverage*/,
1642 float /*foam_fade*/,
1643 int /*resolution*/)
1644{
1645 OceanCache *och = MEM_callocN<OceanCache>("ocean cache data");
1646
1647 return och;
1648}
1649
1650void BKE_ocean_simulate_cache(OceanCache * /*och*/, int /*frame*/) {}
1651
1653 OceanCache * /*och*/,
1654 void (*update_cb)(void *, float progress, int *cancel),
1655 void * /*update_cb_data*/)
1656{
1657 /* unused */
1658 (void)update_cb;
1659}
1660
1662 OceanModifierData const * /*omd*/,
1663 int /*resolution*/)
1664{
1665 return true;
1666}
1667
1668#endif /* WITH_OCEANSIM */
1669
1671{
1673 omd->oceancache = nullptr;
1674 omd->cached = false;
1675}
bool BKE_imbuf_write(ImBuf *ibuf, const char *filepath, const ImageFormatData *imf)
blender::Vector< blender::bke::path_templates::Error > BKE_image_path_from_imtype(char *filepath, const char *base, const char *relbase, const blender::bke::path_templates::VariableMap *template_variables, int frame, char imtype, bool use_ext, bool use_frames, const char *suffix)
bool BKE_ocean_ensure(struct OceanModifierData *omd, int resolution)
float BLI_ocean_spectrum_piersonmoskowitz(const struct Ocean *oc, float kx, float kz)
float BLI_ocean_spectrum_jonswap(const struct Ocean *oc, float kx, float kz)
bool BKE_ocean_is_valid(const struct Ocean *o)
float BLI_ocean_spectrum_texelmarsenarsloe(const struct Ocean *oc, float kx, float kz)
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
BLI_INLINE unsigned int BLI_hash_int_2d(unsigned int kx, unsigned int ky)
Definition BLI_hash.h:51
MINLINE float min_ff(float a, float b)
#define M_PI
#define MINLINE
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
#define FILE_MAX
#define BLI_path_join(...)
Random number functions.
struct RNG * BLI_rng_new(unsigned int seed)
Definition rand.cc:39
void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1)
Definition rand.cc:53
void BLI_rng_seed(struct RNG *rng, unsigned int seed) ATTR_NONNULL(1)
Definition rand.cc:58
float BLI_rng_get_float(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition rand.cc:88
@ TASK_PRIORITY_HIGH
Definition BLI_task.h:53
void * BLI_task_pool_user_data(TaskPool *pool)
Definition task_pool.cc:550
void BLI_task_pool_work_and_wait(TaskPool *pool)
Definition task_pool.cc:535
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition task_range.cc:99
TaskPool * BLI_task_pool_create(void *userdata, eTaskPriority priority)
Definition task_pool.cc:484
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition BLI_task.h:221
void BLI_task_pool_free(TaskPool *pool)
Definition task_pool.cc:521
void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run, void *taskdata, bool free_taskdata, TaskFreeFunction freedata)
Definition task_pool.cc:526
void BLI_rw_mutex_end(ThreadRWMutex *mutex)
Definition threads.cc:482
void BLI_thread_unlock(int type)
Definition threads.cc:333
void BLI_thread_lock(int type)
Definition threads.cc:328
#define THREAD_LOCK_READ
#define THREAD_LOCK_WRITE
void BLI_rw_mutex_lock(ThreadRWMutex *mutex, int mode)
Definition threads.cc:467
void BLI_rw_mutex_init(ThreadRWMutex *mutex)
Definition threads.cc:462
void BLI_rw_mutex_unlock(ThreadRWMutex *mutex)
Definition threads.cc:477
@ LOCK_FFTW
Definition BLI_threads.h:70
#define CLAMP(a, b, c)
#define UNUSED_VARS_NDEBUG(...)
const char * dirname(char *path)
@ MOD_OCEAN_GENERATE_NORMALS
@ MOD_OCEAN_GENERATE_FOAM
@ MOD_OCEAN_GENERATE_SPRAY
@ MOD_OCEAN_SPECTRUM_TEXEL_MARSEN_ARSLOE
@ MOD_OCEAN_SPECTRUM_JONSWAP
@ MOD_OCEAN_SPECTRUM_PIERSON_MOSKOWITZ
@ R_IMF_EXR_CODEC_ZIP
@ R_IMF_CHAN_DEPTH_16
@ R_IMF_IMTYPE_OPENEXR
ImBuf * IMB_load_image_from_filepath(const char *filepath, const int flags, char r_colorspace[IM_MAX_SPACE]=nullptr)
Definition readimage.cc:189
void IMB_freeImBuf(ImBuf *ibuf)
ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
@ IB_float_data
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert * v
#define A
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
static unsigned long seed
Definition btSoftBody.h:39
SIMD_FORCE_INLINE btScalar length2() const
Return the length of the vector squared.
Definition btVector3.h:251
bool is_empty() const
nullptr float
#define logf(x)
#define expf(x)
#define powf(x, y)
#define fmodf(x, y)
#define tanhf(x)
#define printf(...)
#define sin
#define cos
#define abs
#define floor
#define sqrt
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float2 fmod(const float2 a, const float b)
ccl_device_inline float2 fabs(const float2 a)
#define M
#define N
double real
Definition Precision.h:14
MatBase< T, NumCol, NumRow > scale(const MatBase< T, NumCol, NumRow > &mat, const VectorT &scale)
bool BKE_ocean_init_from_modifier(Ocean *, OceanModifierData const *, int)
Definition ocean.cc:1661
bool BKE_ocean_init(Ocean *, int, int, float, float, float, float, float, float, float, float, float, float, int, float, float, short, short, short, short, short, int)
Definition ocean.cc:1578
void BKE_ocean_eval_ij(Ocean *, OceanResult *, int, int)
Definition ocean.cc:1567
OceanCache * BKE_ocean_init_cache(const char *, const char *, int, int, float, float, float, float, int)
Definition ocean.cc:1635
void BKE_ocean_free_cache(OceanCache *och)
Definition ocean.cc:1616
float BKE_ocean_jminus_to_foam(float, float)
Definition ocean.cc:1553
void BKE_ocean_free_modifier_cache(OceanModifierData *omd)
Definition ocean.cc:1670
void BKE_ocean_bake(Ocean *, OceanCache *, void(*update_cb)(void *, float progress, int *cancel), void *)
Definition ocean.cc:1652
void BKE_ocean_free_data(Ocean *)
Definition ocean.cc:1604
void BKE_ocean_cache_eval_ij(OceanCache *, OceanResult *, int, int, int)
Definition ocean.cc:1630
void BKE_ocean_free(Ocean *oc)
Definition ocean.cc:1606
void BKE_ocean_eval_xz(Ocean *, OceanResult *, float, float)
Definition ocean.cc:1563
void BKE_ocean_eval_uv_catrom(Ocean *, OceanResult *, float, float)
Definition ocean.cc:1561
void BKE_ocean_eval_uv(Ocean *, OceanResult *, float, float)
Definition ocean.cc:1558
void BKE_ocean_simulate_cache(OceanCache *, int)
Definition ocean.cc:1650
Ocean * BKE_ocean_add()
Definition ocean.cc:1571
void BKE_ocean_eval_xz_catrom(Ocean *, OceanResult *, float, float)
Definition ocean.cc:1565
void BKE_ocean_cache_eval_uv(OceanCache *, OceanResult *, int, float, float)
Definition ocean.cc:1625
void BKE_ocean_simulate(Ocean *, float, float, float)
Definition ocean.cc:1569
struct Ocean Ocean
#define fabsf
#define sqrtf
#define sinf
#define cosf
#define min(a, b)
Definition sort.cc:36
ImBufFloatBuffer float_buffer
int resolution_x
Definition BKE_ocean.h:51
int resolution_y
Definition BKE_ocean.h:52
const char * bakepath
Definition BKE_ocean.h:36
float * time
Definition BKE_ocean.h:40
struct ImBuf ** ibufs_disp
Definition BKE_ocean.h:28
int duration
Definition BKE_ocean.h:50
float wave_scale
Definition BKE_ocean.h:43
float foam_fade
Definition BKE_ocean.h:46
struct ImBuf ** ibufs_spray
Definition BKE_ocean.h:32
struct ImBuf ** ibufs_norm
Definition BKE_ocean.h:30
struct ImBuf ** ibufs_foam
Definition BKE_ocean.h:29
const char * relbase
Definition BKE_ocean.h:37
struct ImBuf ** ibufs_spray_inverse
Definition BKE_ocean.h:34
float chop_amount
Definition BKE_ocean.h:44
float foam_coverage
Definition BKE_ocean.h:45
struct OceanCache * oceancache
float Eplus[3]
Definition BKE_ocean.h:24
float Jplus
Definition BKE_ocean.h:22
float Eminus[3]
Definition BKE_ocean.h:23
float disp[3]
Definition BKE_ocean.h:16
float Jminus
Definition BKE_ocean.h:21
float normal[3]
Definition BKE_ocean.h:17
float foam
Definition BKE_ocean.h:18
Definition rand.cc:33
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
void ibuf_sample(ImBuf *ibuf, float fx, float fy, float dx, float dy, float result[4])
CCL_NAMESPACE_BEGIN struct Window V