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