From 11c83d843206648a33bcc8b4d754577ec0a51d2a Mon Sep 17 00:00:00 2001 From: Lukas Toenne Date: Sun, 13 Nov 2011 12:17:27 +0000 Subject: Ocean Sim modifier patch by Matt Ebb, Hamed Zaghaghi This adds a new Modifier "Ocean" to simulate large-scale wave motion. Details can be found in the wiki documentation [1], the project homepage [2] and the patch tracker [3] The modifier is disabled by default for now. To enable it, the WITH_OCEANSIM (cmake) / WITH_BF_OCEANSIM (scons) flags have to be set. The code depends on fftw3, so this also has to be enabled. [1] http://wiki.blender.org/index.php/Doc:2.6/Manual/Modifiers/Simulation/Ocean [2] http://www.savetheoceansim.com [3] http://projects.blender.org/tracker/?group_id=9&atid=127&func=detail&aid=28338 --- source/blender/blenkernel/BKE_ocean.h | 108 ++ source/blender/blenkernel/BKE_texture.h | 5 + source/blender/blenkernel/CMakeLists.txt | 11 + source/blender/blenkernel/SConscript | 7 + source/blender/blenkernel/intern/ocean.c | 1407 ++++++++++++++++++++ source/blender/blenkernel/intern/texture.c | 44 +- source/blender/blenloader/intern/readfile.c | 32 + source/blender/blenloader/intern/writefile.c | 1 + source/blender/editors/object/object_intern.h | 1 + source/blender/editors/object/object_modifier.c | 219 +++ source/blender/editors/object/object_ops.c | 1 + source/blender/makesdna/DNA_modifier_types.h | 59 + source/blender/makesdna/DNA_texture_types.h | 24 + source/blender/makesrna/RNA_access.h | 3 + source/blender/makesrna/SConscript | 3 + source/blender/makesrna/intern/CMakeLists.txt | 4 + source/blender/makesrna/intern/rna_modifier.c | 230 ++++ source/blender/makesrna/intern/rna_texture.c | 52 + source/blender/modifiers/CMakeLists.txt | 9 + source/blender/modifiers/MOD_modifiertypes.h | 1 + source/blender/modifiers/SConscript | 3 + source/blender/modifiers/intern/MOD_ocean.c | 561 ++++++++ source/blender/modifiers/intern/MOD_util.c | 1 + source/blender/render/CMakeLists.txt | 2 + .../blender/render/intern/include/texture_ocean.h | 28 + .../blender/render/intern/source/render_texture.c | 11 +- .../blender/render/intern/source/texture_ocean.c | 162 +++ 27 files changed, 2987 insertions(+), 2 deletions(-) create mode 100644 source/blender/blenkernel/BKE_ocean.h create mode 100644 source/blender/blenkernel/intern/ocean.c create mode 100644 source/blender/modifiers/intern/MOD_ocean.c create mode 100644 source/blender/render/intern/include/texture_ocean.h create mode 100644 source/blender/render/intern/source/texture_ocean.c (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_ocean.h b/source/blender/blenkernel/BKE_ocean.h new file mode 100644 index 00000000000..c1f228fe186 --- /dev/null +++ b/source/blender/blenkernel/BKE_ocean.h @@ -0,0 +1,108 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributors: Matt Ebb + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BKE_OCEAN_H +#define BKE_OCEAN_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OceanResult { + float disp[3]; + float normal[3]; + float foam; + + /* raw eigenvalues/vectors */ + float Jminus; + float Jplus; + float Eminus[3]; + float Eplus[3]; +} OceanResult; + + +typedef struct OceanCache { + struct ImBuf **ibufs_disp; + struct ImBuf **ibufs_foam; + struct ImBuf **ibufs_norm; + + char *bakepath; + + /* precalculated for time range */ + float *time; + + /* constant for time range */ + float wave_scale; + float chop_amount; + float foam_coverage; + float foam_fade; + + int start; + int end; + int duration; + int resolution_x; + int resolution_y; + + int baked; +} OceanCache; + + +#define OCEAN_NOT_CACHED 0 +#define OCEAN_CACHING 1 +#define OCEAN_CACHED 2 + + +struct Ocean *BKE_add_ocean(void); +void BKE_free_ocean_data(struct Ocean *oc); +void BKE_free_ocean(struct Ocean *oc); + +void BKE_init_ocean(struct Ocean* o, int M,int N, float Lx, float Lz, float V, float l, float A, float w, float damp, + float alignment, float depth, float time, short do_height_field, short do_chop, short do_normals, short do_jacobian, int seed); +void BKE_simulate_ocean(struct Ocean *o, float t, float scale, float chop_amount); + +/* sampling the ocean surface */ +float BKE_ocean_jminus_to_foam(float jminus, float coverage); +void BKE_ocean_eval_uv(struct Ocean * oc, struct OceanResult *ocr, float u, float v); +void BKE_ocean_eval_uv_catrom(struct Ocean * oc, struct OceanResult *ocr, float u, float v); +void BKE_ocean_eval_xz(struct Ocean * oc, struct OceanResult *ocr, float x, float z); +void BKE_ocean_eval_xz_catrom(struct Ocean * oc, struct OceanResult *ocr, float x, float z); +void BKE_ocean_eval_ij(struct Ocean * oc, struct OceanResult *ocr, int i, int j); + + +/* ocean cache handling */ +struct OceanCache *BKE_init_ocean_cache(char *bakepath, int start, int end, float wave_scale, + float chop_amount, float foam_coverage, float foam_fade, int resolution); +void BKE_simulate_ocean_cache(struct OceanCache *och, int frame); + +void BKE_bake_ocean(struct Ocean *o, struct OceanCache *och, void (*update_cb)(void *, float progress, int *cancel), void *update_cb_data); +void BKE_ocean_cache_eval_uv(struct OceanCache *och, struct OceanResult *ocr, int f, float u, float v); +void BKE_ocean_cache_eval_ij(struct OceanCache *och, struct OceanResult *ocr, int f, int i, int j); + +void BKE_free_ocean_cache(struct OceanCache *och); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h index 508fef8d9a4..52fa52a5899 100644 --- a/source/blender/blenkernel/BKE_texture.h +++ b/source/blender/blenkernel/BKE_texture.h @@ -46,6 +46,7 @@ struct Lamp; struct LampRen; struct Material; struct MTex; +struct OceanTex; struct ParticleSettings; struct PluginTex; struct PointDensity; @@ -125,6 +126,10 @@ void BKE_free_voxeldata(struct VoxelData *vd); struct VoxelData *BKE_add_voxeldata(void); struct VoxelData *BKE_copy_voxeldata(struct VoxelData *vd); +void BKE_free_oceantex(struct OceanTex *ot); +struct OceanTex *BKE_add_oceantex(void); +struct OceanTex *BKE_copy_oceantex(struct OceanTex *ot); + int BKE_texture_dependsOnTime(const struct Tex *texture); #ifdef __cplusplus diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 1fc851bfa72..4e7561a1bc8 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -117,6 +117,7 @@ set(SRC intern/multires.c intern/nla.c intern/node.c + intern/ocean.c intern/object.c intern/packedFile.c intern/paint.c @@ -204,6 +205,7 @@ set(SRC BKE_multires.h BKE_nla.h BKE_node.h + BKE_ocean.h BKE_object.h BKE_packedFile.h BKE_paint.h @@ -341,6 +343,10 @@ if(WITH_MOD_SMOKE) add_definitions(-DWITH_SMOKE) endif() +if(WITH_OCEANSIM) + add_definitions(-DWITH_OCEANSIM) +endif() + if(WITH_JACK) add_definitions(-DWITH_JACK) endif() @@ -378,6 +384,11 @@ if(WITH_LIBMV) add_definitions(-DWITH_LIBMV) endif() +if(WITH_FFTW3) + list(APPEND INC_SYS ${FFTW3_INCLUDE_DIRS}) + add_definitions(-DFFTW3=1) +endif() + ## Warnings as errors, this is too strict! #if(MSVC) # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX") diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript index 48a68c433a6..62a8aa8362f 100644 --- a/source/blender/blenkernel/SConscript +++ b/source/blender/blenkernel/SConscript @@ -82,6 +82,9 @@ if env['OURPLATFORM'] == 'darwin': if env['WITH_BF_FLUID']: defs.append('WITH_MOD_FLUID') +if env['WITH_BF_OCEANSIM']: + defs.append('WITH_OCEANSIM') + if env['WITH_BF_LZO']: incs += ' #/extern/lzo/minilzo' defs.append('WITH_LZO') @@ -100,6 +103,10 @@ if env['WITH_BF_LIBMV']: incs += ' #/extern/libmv' defs.append('WITH_LIBMV') +if env['WITH_BF_FFTW3']: + defs.append('FFTW3=1') + incs += ' ' + env['BF_FFTW3_INC'] + if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'): incs += ' ' + env['BF_PTHREADS_INC'] diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c new file mode 100644 index 00000000000..455acd2130f --- /dev/null +++ b/source/blender/blenkernel/intern/ocean.c @@ -0,0 +1,1407 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributors: Matt Ebb, Hamed Zaghaghi + * Based on original code by Drew Whitehouse / Houdini Ocean Toolkit + * OpenMP hints by Christian Schnellhammer + * + * ***** END GPL LICENSE BLOCK ***** + */ + + +#include +#include + +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_scene_types.h" + +#include "BKE_image.h" +#include "BKE_ocean.h" +#include "BKE_utildefines.h" + +#include "BKE_global.h" // XXX TESTING + +#include "BLI_math_base.h" +#include "BLI_math_inline.h" +#include "BLI_rand.h" +#include "BLI_string.h" +#include "BLI_threads.h" +#include "BLI_utildefines.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "RE_render_ext.h" + +#ifdef WITH_OCEANSIM + +// Ocean code +#include "fftw3.h" + +#define GRAVITY 9.81f + +typedef struct Ocean { + /* ********* input parameters to the sim ********* */ + float _V; + float _l; + float _w; + float _A; + float _damp_reflections; + float _wind_alignment; + float _depth; + + float _wx; + float _wz; + + float _L; + + /* dimensions of computational grid */ + int _M; + int _N; + + /* spatial size of computational grid */ + float _Lx; + float _Lz; + + float normalize_factor; // init w + float time; + + short _do_disp_y; + short _do_normals; + short _do_chop; + short _do_jacobian; + + /* mutex for threaded texture access */ + ThreadRWMutex oceanmutex; + + /* ********* sim data arrays ********* */ + + /* two dimensional arrays of complex */ + fftw_complex *_fft_in; // init w sim w + fftw_complex *_fft_in_x; // init w sim w + fftw_complex *_fft_in_z; // init w sim w + fftw_complex *_fft_in_jxx; // init w sim w + fftw_complex *_fft_in_jzz; // init w sim w + fftw_complex *_fft_in_jxz; // init w sim w + fftw_complex *_fft_in_nx; // init w sim w + fftw_complex *_fft_in_nz; // init w sim w + fftw_complex *_htilda; // init w sim w (only once) + + /* fftw "plans" */ + fftw_plan _disp_y_plan; // init w sim r + fftw_plan _disp_x_plan; // init w sim r + fftw_plan _disp_z_plan; // init w sim r + fftw_plan _N_x_plan; // init w sim r + fftw_plan _N_z_plan; // init w sim r + fftw_plan _Jxx_plan; // init w sim r + fftw_plan _Jxz_plan; // init w sim r + fftw_plan _Jzz_plan; // init w sim r + + /* two dimensional arrays of float */ + double * _disp_y; // init w sim w via plan? + double * _N_x; // init w sim w via plan? + /*float * _N_y; all member of this array has same values, so convert this array to a float to reduce memory usage (MEM01)*/ + double _N_y; // sim w ********* can be rearranged? + double * _N_z; // init w sim w via plan? + double * _disp_x; // init w sim w via plan? + double * _disp_z; // init w sim w via plan? + + /* two dimensional arrays of float */ + /* Jacobian and minimum eigenvalue */ + double * _Jxx; // init w sim w + double * _Jzz; // init w sim w + double * _Jxz; // init w sim w + + /* one dimensional float array */ + float * _kx; // init w sim r + float * _kz; // init w sim r + + /* two dimensional complex array */ + fftw_complex * _h0; // init w sim r + fftw_complex * _h0_minus; // init w sim r + + /* two dimensional float array */ + float * _k; // init w sim r +} Ocean; + + + +static float nextfr(float min, float max) +{ + return BLI_frand()*(min-max)+max; +} + +static float gaussRand (void) +{ + float x; // Note: to avoid numerical problems with very small + float y; // numbers, we make these variables singe-precision + float length2; // floats, but later we call the double-precision log() + // and sqrt() functions instead of logf() and sqrtf(). + do + { + x = (float) (nextfr (-1, 1)); + y = (float)(nextfr (-1, 1)); + length2 = x * x + y * y; + } + while (length2 >= 1 || length2 == 0); + + return x * sqrt (-2 * log (length2) / length2); +} + +/** + * Som usefull functions + * */ +MINLINE float lerp(float a,float b,float f) +{ + return a + (b-a)*f; +} + +MINLINE float catrom(float p0,float p1,float p2,float p3,float f) +{ + return 0.5 *((2 * p1) + + (-p0 + p2) * f + + (2*p0 - 5*p1 + 4*p2 - p3) * f*f + + (-p0 + 3*p1- 3*p2 + p3) * f*f*f); +} + +MINLINE float omega(float k, float depth) +{ + return sqrt(GRAVITY*k * tanh(k*depth)); +} + +// modified Phillips spectrum +static float Ph(struct Ocean* o, float kx,float kz ) +{ + float tmp; + float k2 = kx*kx + kz*kz; + + if (k2 == 0.0) + { + return 0.0; // no DC component + } + + // damp out the waves going in the direction opposite the wind + tmp = (o->_wx * kx + o->_wz * kz)/sqrt(k2); + if (tmp < 0) + { + tmp *= o->_damp_reflections; + } + + return o->_A * exp( -1.0f / (k2*(o->_L*o->_L))) * exp(-k2 * (o->_l*o->_l)) * pow(fabs(tmp),o->_wind_alignment) / (k2*k2); +} + +static void compute_eigenstuff(struct OceanResult *ocr, float jxx,float jzz,float jxz) +{ + float a,b,qplus,qminus; + a = jxx + jzz; + b = sqrt((jxx - jzz)*(jxx - jzz) + 4 * jxz * jxz); + + ocr->Jminus = 0.5*(a-b); + ocr->Jplus = 0.5*(a+b); + + qplus = (ocr->Jplus - jxx)/jxz; + qminus = (ocr->Jminus - jxx)/jxz; + + a = sqrt(1 + qplus*qplus); + b = sqrt(1 + qminus*qminus); + + ocr->Eplus[0] = 1.0/ a; + ocr->Eplus[1] = 0.0; + ocr->Eplus[2] = qplus/a; + + ocr->Eminus[0] = 1.0/b; + ocr->Eminus[1] = 0.0; + ocr->Eminus[2] = qminus/b; +} + +/* + * instead of Complex.h + * in fftw.h "fftw_complex" typedefed as double[2] + * below you can see functions are needed to work with such complex numbers. + * */ +static void init_complex(fftw_complex cmpl, float real, float image) +{ + cmpl[0] = real; + cmpl[1] = image; +} + +#if 0 // unused +static void add_complex_f(fftw_complex res, fftw_complex cmpl, float f) +{ + res[0] = cmpl[0] + f; + res[1] = cmpl[1]; +} +#endif + +static void add_comlex_c(fftw_complex res, fftw_complex cmpl1, fftw_complex cmpl2) +{ + res[0] = cmpl1[0] + cmpl2[0]; + res[1] = cmpl1[1] + cmpl2[1]; +} + +static void mul_complex_f(fftw_complex res, fftw_complex cmpl, float f) +{ + res[0] = cmpl[0]*f; + res[1] = cmpl[1]*f; +} + +static void mul_complex_c(fftw_complex res, fftw_complex cmpl1, fftw_complex cmpl2) +{ + fftwf_complex temp; + temp[0] = cmpl1[0]*cmpl2[0]-cmpl1[1]*cmpl2[1]; + temp[1] = cmpl1[0]*cmpl2[1]+cmpl1[1]*cmpl2[0]; + res[0] = temp[0]; + res[1] = temp[1]; +} + +static float real_c(fftw_complex cmpl) +{ + return cmpl[0]; +} + +static float image_c(fftw_complex cmpl) +{ + return cmpl[1]; +} + +static void conj_complex(fftw_complex res, fftw_complex cmpl1) +{ + res[0] = cmpl1[0]; + res[1] = -cmpl1[1]; +} + +static void exp_complex(fftw_complex res, fftw_complex cmpl) +{ + float r = expf(cmpl[0]); + + res[0] = cos(cmpl[1])*r; + res[1] = sin(cmpl[1])*r; +} + +float BKE_ocean_jminus_to_foam(float jminus, float coverage) { + float foam = jminus * -0.005 + coverage; + CLAMP(foam, 0.0, 1.0); + return foam*foam; +} + +void BKE_ocean_eval_uv(struct Ocean *oc, struct OceanResult *ocr, float u,float v) +{ + int i0,i1,j0,j1; + float frac_x,frac_z; + float uu,vv; + + // first wrap the texture so 0 <= (u,v) < 1 + u = fmod(u,1.0f); + v = fmod(v,1.0f); + + if (u < 0) u += 1.0f; + if (v < 0) v += 1.0f; + + BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ); + + uu = u * oc->_M; + vv = v * oc->_N; + + i0 = (int)floor(uu); + j0 = (int)floor(vv); + + i1 = (i0 + 1); + j1 = (j0 + 1); + + frac_x = uu - i0; + frac_z = vv - j0; + + i0 = i0 % oc->_M; + j0 = j0 % oc->_N; + + i1 = i1 % oc->_M; + j1 = j1 % oc->_N; + + +#define BILERP(m) (lerp(lerp(m[i0*oc->_N+j0],m[i1*oc->_N+j0],frac_x),lerp(m[i0*oc->_N+j1],m[i1*oc->_N+j1],frac_x),frac_z)) + { + if (oc->_do_disp_y) { + ocr->disp[1] = BILERP(oc->_disp_y); + } + + if (oc->_do_normals) { + ocr->normal[0] = BILERP(oc->_N_x); + ocr->normal[1] = oc->_N_y/*BILERP(oc->_N_y) (MEM01)*/; + ocr->normal[2] = BILERP(oc->_N_z); + } + + if (oc->_do_chop) { + ocr->disp[0] = BILERP(oc->_disp_x); + ocr->disp[2] = BILERP(oc->_disp_z); + } else { + ocr->disp[0] = 0.0; + ocr->disp[2] = 0.0; + } + + if (oc->_do_jacobian) { + compute_eigenstuff(ocr, BILERP(oc->_Jxx),BILERP(oc->_Jzz),BILERP(oc->_Jxz)); + } + } +#undef BILERP + + BLI_rw_mutex_unlock(&oc->oceanmutex); +} + +// use catmullrom interpolation rather than linear +void BKE_ocean_eval_uv_catrom(struct Ocean *oc, struct OceanResult *ocr, float u,float v) +{ + int i0,i1,i2,i3,j0,j1,j2,j3; + float frac_x,frac_z; + float uu,vv; + + // first wrap the texture so 0 <= (u,v) < 1 + u = fmod(u,1.0f); + v = fmod(v,1.0f); + + if (u < 0) u += 1.0f; + if (v < 0) v += 1.0f; + + BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ); + + uu = u * oc->_M; + vv = v * oc->_N; + + i1 = (int)floor(uu); + j1 = (int)floor(vv); + + i2 = (i1 + 1); + j2 = (j1 + 1); + + frac_x = uu - i1; + frac_z = vv - j1; + + i1 = i1 % oc->_M; + j1 = j1 % oc->_N; + + i2 = i2 % oc->_M; + j2 = j2 % oc->_N; + + i0 = (i1-1); + i3 = (i2+1); + i0 = i0 < 0 ? i0 + oc->_M : i0; + i3 = i3 >= oc->_M ? i3 - oc->_M : i3; + + j0 = (j1-1); + j3 = (j2+1); + j0 = j0 < 0 ? j0 + oc->_N : j0; + j3 = j3 >= oc->_N ? j3 - oc->_N : j3; + +#define INTERP(m) catrom(catrom(m[i0*oc->_N+j0],m[i1*oc->_N+j0],m[i2*oc->_N+j0],m[i3*oc->_N+j0],frac_x),\ +catrom(m[i0*oc->_N+j1],m[i1*oc->_N+j1],m[i2*oc->_N+j1],m[i3*oc->_N+j1],frac_x),\ +catrom(m[i0*oc->_N+j2],m[i1*oc->_N+j2],m[i2*oc->_N+j2],m[i3*oc->_N+j2],frac_x),\ +catrom(m[i0*oc->_N+j3],m[i1*oc->_N+j3],m[i2*oc->_N+j3],m[i3*oc->_N+j3],frac_x),\ +frac_z) + + { + if (oc->_do_disp_y) + { + ocr->disp[1] = INTERP(oc->_disp_y) ; + } + if (oc->_do_normals) + { + ocr->normal[0] = INTERP(oc->_N_x); + ocr->normal[1] = oc->_N_y/*INTERP(oc->_N_y) (MEM01)*/; + ocr->normal[2] = INTERP(oc->_N_z); + } + if (oc->_do_chop) + { + ocr->disp[0] = INTERP(oc->_disp_x); + ocr->disp[2] = INTERP(oc->_disp_z); + } + else + { + ocr->disp[0] = 0.0; + ocr->disp[2] = 0.0; + } + + if (oc->_do_jacobian) + { + compute_eigenstuff(ocr, INTERP(oc->_Jxx),INTERP(oc->_Jzz),INTERP(oc->_Jxz)); + } + } +#undef INTERP + + BLI_rw_mutex_unlock(&oc->oceanmutex); + +} + +void BKE_ocean_eval_xz(struct Ocean *oc, struct OceanResult *ocr, float x,float z) +{ + BKE_ocean_eval_uv(oc, ocr, x/oc->_Lx,z/oc->_Lz); +} + +void BKE_ocean_eval_xz_catrom(struct Ocean *oc, struct OceanResult *ocr, float x,float z) +{ + BKE_ocean_eval_uv_catrom(oc, ocr, x/oc->_Lx,z/oc->_Lz); +} + +// note that this doesn't wrap properly for i,j < 0, but its +// not really meant for that being just a way to get the raw data out +// to save in some image format. +void BKE_ocean_eval_ij(struct Ocean *oc, struct OceanResult *ocr, int i,int j) +{ + BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ); + + i = abs(i) % oc->_M; + j = abs(j) % oc->_N; + + ocr->disp[1] = oc->_do_disp_y ? oc->_disp_y[i*oc->_N+j] : 0.0f; + + if (oc->_do_chop) + { + ocr->disp[0] = oc->_disp_x[i*oc->_N+j]; + ocr->disp[2] = oc->_disp_z[i*oc->_N+j]; + } + else + { + ocr->disp[0] = 0.0f; + ocr->disp[2] = 0.0f; + } + + if (oc->_do_normals) + { + ocr->normal[0] = oc->_N_x[i*oc->_N+j]; + ocr->normal[1] = oc->_N_y/*oc->_N_y[i*oc->_N+j] (MEM01)*/; + ocr->normal[2] = oc->_N_z[i*oc->_N+j]; + } + + if (oc->_do_jacobian) + { + compute_eigenstuff(ocr, oc->_Jxx[i*oc->_N+j],oc->_Jzz[i*oc->_N+j],oc->_Jxz[i*oc->_N+j]); + } + + BLI_rw_mutex_unlock(&oc->oceanmutex); +} + +void BKE_simulate_ocean(struct Ocean *o, float t, float scale, float chop_amount) +{ + int i, j; + + scale *= o->normalize_factor; + + BLI_rw_mutex_lock(&o->oceanmutex, THREAD_LOCK_WRITE); + + // compute a new htilda + #pragma omp parallel for private(i, j) + for (i = 0 ; i < o->_M ; ++i) + { + // note the <= _N/2 here, see the fftw doco about + // the mechanics of the complex->real fft storage + for ( j = 0 ; j <= o->_N / 2 ; ++j) + { + fftw_complex exp_param1; + fftw_complex exp_param2; + fftw_complex conj_param; + + + init_complex(exp_param1, 0.0, omega(o->_k[i*(1+o->_N/2)+j],o->_depth)*t); + init_complex(exp_param2, 0.0, -omega(o->_k[i*(1+o->_N/2)+j],o->_depth)*t); + exp_complex(exp_param1, exp_param1); + exp_complex(exp_param2, exp_param2); + conj_complex(conj_param, o->_h0_minus[i*o->_N+j]); + + mul_complex_c(exp_param1, o->_h0[i*o->_N+j], exp_param1); + mul_complex_c(exp_param2, conj_param, exp_param2); + + add_comlex_c(o->_htilda[i*(1+o->_N/2)+j], exp_param1, exp_param2); + mul_complex_f(o->_fft_in[i*(1+o->_N/2)+j], o->_htilda[i*(1+o->_N/2)+j], scale); + } + } + + #pragma omp parallel sections private(i, j) + { + + #pragma omp section + { + if (o->_do_disp_y) + { + // y displacement + fftw_execute(o->_disp_y_plan); + } + } // section 1 + + #pragma omp section + { + if (o->_do_chop) + { + // x displacement + for ( i = 0 ; i < o->_M ; ++i) + { + for ( j = 0 ; j <= o->_N / 2 ; ++j) + { + fftw_complex mul_param; + fftw_complex minus_i; + + init_complex(minus_i, 0.0, -1.0); + init_complex(mul_param, -scale, 0); + mul_complex_f(mul_param, mul_param, chop_amount); + mul_complex_c(mul_param, mul_param, minus_i); + mul_complex_c(mul_param, mul_param, o->_htilda[i*(1+o->_N/2)+j]); + mul_complex_f(mul_param, mul_param, (o->_k[i*(1+o->_N/2)+j] == 0.0 ? 0.0 : o->_kx[i] / o->_k[i*(1+o->_N/2)+j])); + init_complex(o->_fft_in_x[i*(1+o->_N/2)+j], real_c(mul_param), image_c(mul_param)); + } + } + fftw_execute(o->_disp_x_plan); + } + } //section 2 + + #pragma omp section + { + if (o->_do_chop) + { + // z displacement + for ( i = 0 ; i < o->_M ; ++i) + { + for ( j = 0 ; j <= o->_N / 2 ; ++j) + { + fftw_complex mul_param; + fftw_complex minus_i; + + init_complex(minus_i, 0.0, -1.0); + init_complex(mul_param, -scale, 0); + mul_complex_f(mul_param, mul_param, chop_amount); + mul_complex_c(mul_param, mul_param, minus_i); + mul_complex_c(mul_param, mul_param, o->_htilda[i*(1+o->_N/2)+j]); + mul_complex_f(mul_param, mul_param, (o->_k[i*(1+o->_N/2)+j] == 0.0 ? 0.0 : o->_kz[j] / o->_k[i*(1+o->_N/2)+j])); + init_complex(o->_fft_in_z[i*(1+o->_N/2)+j], real_c(mul_param), image_c(mul_param)); + } + } + fftw_execute(o->_disp_z_plan); + } + } // section 3 + + #pragma omp section + { + if (o->_do_jacobian) + { + // Jxx + for ( i = 0 ; i < o->_M ; ++i) + { + for ( j = 0 ; j <= o->_N / 2 ; ++j) + { + fftw_complex mul_param; + + //init_complex(mul_param, -scale, 0); + init_complex(mul_param, -1, 0); + + mul_complex_f(mul_param, mul_param, chop_amount); + mul_complex_c(mul_param, mul_param, o->_htilda[i*(1+o->_N/2)+j]); + mul_complex_f(mul_param, mul_param, (o->_k[i*(1+o->_N/2)+j] == 0.0 ? 0.0 : o->_kx[i]*o->_kx[i] / o->_k[i*(1+o->_N/2)+j])); + init_complex(o->_fft_in_jxx[i*(1+o->_N/2)+j], real_c(mul_param), image_c(mul_param)); + } + } + fftw_execute(o->_Jxx_plan); + + for ( i = 0 ; i < o->_M ; ++i) + { + for ( j = 0 ; j < o->_N ; ++j) + { + o->_Jxx[i*o->_N+j] += 1.0; + } + } + } + } // section 4 + + #pragma omp section + { + if (o->_do_jacobian) + { + // Jzz + for ( i = 0 ; i < o->_M ; ++i) + { + for ( j = 0 ; j <= o->_N / 2 ; ++j) + { + fftw_complex mul_param; + + //init_complex(mul_param, -scale, 0); + init_complex(mul_param, -1, 0); + + mul_complex_f(mul_param, mul_param, chop_amount); + mul_complex_c(mul_param, mul_param, o->_htilda[i*(1+o->_N/2)+j]); + mul_complex_f(mul_param, mul_param, (o->_k[i*(1+o->_N/2)+j] == 0.0 ? 0.0 : o->_kz[j]*o->_kz[j] / o->_k[i*(1+o->_N/2)+j])); + init_complex(o->_fft_in_jzz[i*(1+o->_N/2)+j], real_c(mul_param), image_c(mul_param)); + } + } + fftw_execute(o->_Jzz_plan); + for ( i = 0 ; i < o->_M ; ++i) + { + for ( j = 0 ; j < o->_N ; ++j) + { + o->_Jzz[i*o->_N+j] += 1.0; + } + } + } + } // section 5 + + #pragma omp section + { + if (o->_do_jacobian) + { + // Jxz + for ( i = 0 ; i < o->_M ; ++i) + { + for ( j = 0 ; j <= o->_N / 2 ; ++j) + { + fftw_complex mul_param; + + //init_complex(mul_param, -scale, 0); + init_complex(mul_param, -1, 0); + + mul_complex_f(mul_param, mul_param, chop_amount); + mul_complex_c(mul_param, mul_param, o->_htilda[i*(1+o->_N/2)+j]); + mul_complex_f(mul_param, mul_param, (o->_k[i*(1+o->_N/2)+j] == 0.0 ? 0.0 : o->_kx[i]*o->_kz[j] / o->_k[i*(1+o->_N/2)+j])); + init_complex(o->_fft_in_jxz[i*(1+o->_N/2)+j], real_c(mul_param), image_c(mul_param)); + } + } + fftw_execute(o->_Jxz_plan); + } + } // section 6 + + #pragma omp section + { + // fft normals + if (o->_do_normals) + { + for ( i = 0 ; i < o->_M ; ++i) + { + for ( j = 0 ; j <= o->_N / 2 ; ++j) + { + fftw_complex mul_param; + + init_complex(mul_param, 0.0, -1.0); + mul_complex_c(mul_param, mul_param, o->_htilda[i*(1+o->_N/2)+j]); + mul_complex_f(mul_param, mul_param, o->_kx[i]); + init_complex(o->_fft_in_nx[i*(1+o->_N/2)+j], real_c(mul_param), image_c(mul_param)); + } + } + fftw_execute(o->_N_x_plan); + + } + } // section 7 + + #pragma omp section + { + if (o->_do_normals) + { + for ( i = 0 ; i < o->_M ; ++i) + { + for ( j = 0 ; j <= o->_N / 2 ; ++j) + { + fftw_complex mul_param; + + init_complex(mul_param, 0.0, -1.0); + mul_complex_c(mul_param, mul_param, o->_htilda[i*(1+o->_N/2)+j]); + mul_complex_f(mul_param, mul_param, o->_kz[i]); + init_complex(o->_fft_in_nz[i*(1+o->_N/2)+j], real_c(mul_param), image_c(mul_param)); + } + } + fftw_execute(o->_N_z_plan); + + /*for ( i = 0 ; i < o->_M ; ++i) + { + for ( j = 0 ; j < o->_N ; ++j) + { + o->_N_y[i*o->_N+j] = 1.0f/scale; + } + } + (MEM01)*/ + o->_N_y = 1.0f/scale; + } + } // section 8 + + } // omp sections + + BLI_rw_mutex_unlock(&o->oceanmutex); +} + +static void set_height_normalize_factor(struct Ocean *oc) +{ + float res = 1.0; + float max_h = 0.0; + + int i,j; + + if (!oc->_do_disp_y) return; + + oc->normalize_factor = 1.0; + + BKE_simulate_ocean(oc, 0.0, 1.0, 0); + + BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ); + + for (i = 0; i < oc->_M; ++i) + { + for (j = 0; j < oc->_N; ++j) + { + if( max_h < fabsf(oc->_disp_y[i*oc->_N+j])) + { + max_h = fabsf(oc->_disp_y[i*oc->_N+j]); + } + } + } + + BLI_rw_mutex_unlock(&oc->oceanmutex); + + if (max_h == 0.0) max_h = 0.00001f; // just in case ... + + res = 1.0f / (max_h); + + oc->normalize_factor = res; +} + +struct Ocean *BKE_add_ocean(void) +{ + Ocean *oc = MEM_callocN(sizeof(Ocean), "ocean sim data"); + + BLI_rw_mutex_init(&oc->oceanmutex); + + return oc; +} + +void BKE_init_ocean(struct Ocean* o, int M,int N, float Lx, float Lz, float V, float l, float A, float w, float damp, + float alignment, float depth, float time, short do_height_field, short do_chop, short do_normals, short do_jacobian, int seed) +{ + int i,j,ii; + + BLI_rw_mutex_lock(&o->oceanmutex, THREAD_LOCK_WRITE); + + o->_M = M; + o->_N = N; + o->_V = V; + o->_l = l; + o->_A = A; + o->_w = w; + o->_damp_reflections = 1.0 - damp; + o->_wind_alignment = alignment; + o->_depth = depth; + o->_Lx = Lx; + o->_Lz = Lz; + o->_wx = cos(w); + o->_wz = -sin(w); // wave direction + o->_L = V*V / GRAVITY; // largest wave for a given velocity V + o->time = time; + + o->_do_disp_y = do_height_field; + o->_do_normals = do_normals; + o->_do_chop = do_chop; + o->_do_jacobian = do_jacobian; + + o->_k = (float*) MEM_mallocN(M * (1+N/2) * sizeof(float), "ocean_k"); + o->_h0 = (fftw_complex*) MEM_mallocN(M * N * sizeof(fftw_complex), "ocean_h0"); + o->_h0_minus = (fftw_complex*) MEM_mallocN(M * N * sizeof(fftw_complex), "ocean_h0_minus"); + o->_kx = (float*) MEM_mallocN(o->_M * sizeof(float), "ocean_kx"); + o->_kz = (float*) MEM_mallocN(o->_N * sizeof(float), "ocean_kz"); + + // make this robust in the face of erroneous usage + if (o->_Lx == 0.0) + o->_Lx = 0.001; + + if (o->_Lz == 0.0) + o->_Lz = 0.001; + + // the +ve components and DC + for (i = 0 ; i <= o->_M/2 ; ++i) + o->_kx[i] = 2.0f * M_PI * i / o->_Lx; + + // the -ve components + for (i = o->_M-1,ii=0 ; i > o->_M/2 ; --i,++ii) + o->_kx[i] = -2.0f * M_PI * ii / o->_Lx; + + // the +ve components and DC + for (i = 0 ; i <= o->_N/2 ; ++i) + o->_kz[i] = 2.0f * M_PI * i / o->_Lz; + + // the -ve components + for (i = o->_N-1,ii=0 ; i > o->_N/2 ; --i,++ii) + o->_kz[i] = -2.0f * M_PI * ii / o->_Lz; + + // pre-calculate the k matrix + for (i = 0 ; i < o->_M ; ++i) + for (j = 0 ; j <= o->_N / 2 ; ++j) + o->_k[i*(1+o->_N/2)+j] = sqrt(o->_kx[i]*o->_kx[i] + o->_kz[j]*o->_kz[j] ); + + /*srand(seed);*/ + BLI_srand(seed); + + for (i = 0 ; i < o->_M ; ++i) + { + for (j = 0 ; j < o->_N ; ++j) + { + float r1 = gaussRand(); + float r2 = gaussRand(); + + fftw_complex r1r2; + init_complex(r1r2, r1, r2); + mul_complex_f(o->_h0[i*o->_N+j], r1r2, (float)(sqrt(Ph(o, o->_kx[i], o->_kz[j]) / 2.0f))); + mul_complex_f(o->_h0_minus[i*o->_N+j], r1r2, (float)(sqrt(Ph(o, -o->_kx[i],-o->_kz[j]) / 2.0f))); + } + } + + o->_fft_in = (fftw_complex*) MEM_mallocN(o->_M * (1+o->_N/2) * sizeof(fftw_complex), "ocean_fft_in"); + o->_htilda = (fftw_complex*) MEM_mallocN(o->_M * (1+o->_N/2) * sizeof(fftw_complex), "ocean_htilda"); + + if (o->_do_disp_y){ + o->_disp_y = (double*) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_y"); + o->_disp_y_plan = fftw_plan_dft_c2r_2d(o->_M,o->_N, o->_fft_in, o->_disp_y, FFTW_ESTIMATE); + } + + if (o->_do_normals){ + o->_fft_in_nx = (fftw_complex*) MEM_mallocN(o->_M * (1+o->_N/2) * sizeof(fftw_complex), "ocean_fft_in_nx"); + o->_fft_in_nz = (fftw_complex*) MEM_mallocN(o->_M * (1+o->_N/2) * sizeof(fftw_complex), "ocean_fft_in_nz"); + + o->_N_x = (double*) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_N_x"); + /*o->_N_y = (float*) fftwf_malloc(o->_M * o->_N * sizeof(float)); (MEM01)*/ + o->_N_z = (double*) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_N_z"); + + o->_N_x_plan = fftw_plan_dft_c2r_2d(o->_M,o->_N, o->_fft_in_nx, o->_N_x, FFTW_ESTIMATE); + o->_N_z_plan = fftw_plan_dft_c2r_2d(o->_M,o->_N, o->_fft_in_nz, o->_N_z, FFTW_ESTIMATE); + } + + if (o->_do_chop){ + o->_fft_in_x = (fftw_complex*) MEM_mallocN(o->_M * (1+o->_N/2) * sizeof(fftw_complex), "ocean_fft_in_x"); + o->_fft_in_z = (fftw_complex*) MEM_mallocN(o->_M * (1+o->_N/2) * sizeof(fftw_complex), "ocean_fft_in_z"); + + o->_disp_x = (double*) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_x"); + o->_disp_z = (double*) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_z"); + + o->_disp_x_plan = fftw_plan_dft_c2r_2d(o->_M,o->_N, o->_fft_in_x, o->_disp_x, FFTW_ESTIMATE); + o->_disp_z_plan = fftw_plan_dft_c2r_2d(o->_M,o->_N, o->_fft_in_z, o->_disp_z, FFTW_ESTIMATE); + } + if (o->_do_jacobian){ + o->_fft_in_jxx = (fftw_complex*) MEM_mallocN(o->_M * (1+o->_N/2) * sizeof(fftw_complex), "ocean_fft_in_jxx"); + o->_fft_in_jzz = (fftw_complex*) MEM_mallocN(o->_M * (1+o->_N/2) * sizeof(fftw_complex), "ocean_fft_in_jzz"); + o->_fft_in_jxz = (fftw_complex*) MEM_mallocN(o->_M * (1+o->_N/2) * sizeof(fftw_complex), "ocean_fft_in_jxz"); + + o->_Jxx = (double*) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jxx"); + o->_Jzz = (double*) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jzz"); + o->_Jxz = (double*) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jxz"); + + o->_Jxx_plan = fftw_plan_dft_c2r_2d(o->_M,o->_N, o->_fft_in_jxx, o->_Jxx, FFTW_ESTIMATE); + o->_Jzz_plan = fftw_plan_dft_c2r_2d(o->_M,o->_N, o->_fft_in_jzz, o->_Jzz, FFTW_ESTIMATE); + o->_Jxz_plan = fftw_plan_dft_c2r_2d(o->_M,o->_N, o->_fft_in_jxz, o->_Jxz, FFTW_ESTIMATE); + } + + BLI_rw_mutex_unlock(&o->oceanmutex); + + set_height_normalize_factor(o); + +} + +void BKE_free_ocean_data(struct Ocean *oc) +{ + if(!oc) return; + + BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_WRITE); + + if (oc->_do_disp_y) + { + fftw_destroy_plan(oc->_disp_y_plan); + MEM_freeN(oc->_disp_y); + } + + if (oc->_do_normals) + { + MEM_freeN(oc->_fft_in_nx); + MEM_freeN(oc->_fft_in_nz); + fftw_destroy_plan(oc->_N_x_plan); + fftw_destroy_plan(oc->_N_z_plan); + MEM_freeN(oc->_N_x); + /*fftwf_free(oc->_N_y); (MEM01)*/ + MEM_freeN(oc->_N_z); + } + + if (oc->_do_chop) + { + MEM_freeN(oc->_fft_in_x); + MEM_freeN(oc->_fft_in_z); + fftw_destroy_plan(oc->_disp_x_plan); + fftw_destroy_plan(oc->_disp_z_plan); + MEM_freeN(oc->_disp_x); + MEM_freeN(oc->_disp_z); + } + + if (oc->_do_jacobian) + { + MEM_freeN(oc->_fft_in_jxx); + MEM_freeN(oc->_fft_in_jzz); + MEM_freeN(oc->_fft_in_jxz); + fftw_destroy_plan(oc->_Jxx_plan); + fftw_destroy_plan(oc->_Jzz_plan); + fftw_destroy_plan(oc->_Jxz_plan); + MEM_freeN(oc->_Jxx); + MEM_freeN(oc->_Jzz); + MEM_freeN(oc->_Jxz); + } + + if (oc->_fft_in) + MEM_freeN(oc->_fft_in); + + /* check that ocean data has been initialised */ + if (oc->_htilda) { + MEM_freeN(oc->_htilda); + MEM_freeN(oc->_k); + MEM_freeN(oc->_h0); + MEM_freeN(oc->_h0_minus); + MEM_freeN(oc->_kx); + MEM_freeN(oc->_kz); + } + + BLI_rw_mutex_unlock(&oc->oceanmutex); +} + +void BKE_free_ocean(struct Ocean *oc) +{ + if(!oc) return; + + BKE_free_ocean_data(oc); + BLI_rw_mutex_end(&oc->oceanmutex); + + MEM_freeN(oc); +} + +#undef GRAVITY + + +/* ********* Baking/Caching ********* */ + + +#define CACHE_TYPE_DISPLACE 1 +#define CACHE_TYPE_FOAM 2 +#define CACHE_TYPE_NORMAL 3 + +static void cache_filename(char *string, char *path, int frame, int type) +{ + char *cachepath=NULL; + + switch(type) { + case CACHE_TYPE_FOAM: + cachepath = BLI_strdupcat(path, "foam_"); + break; + case CACHE_TYPE_NORMAL: + cachepath = BLI_strdupcat(path, "normal_"); + break; + case CACHE_TYPE_DISPLACE: + default: + cachepath = BLI_strdupcat(path, "disp_"); + break; + } + + BKE_makepicstring(string, cachepath, frame, R_OPENEXR, 1, TRUE); + + MEM_freeN(cachepath); +} + +void BKE_free_ocean_cache(struct OceanCache *och) +{ + int i, f=0; + + if (!och) return; + + if (och->ibufs_disp) { + for (i=och->start, f=0; i<=och->end; i++, f++) + { + if (och->ibufs_disp[f]) { + IMB_freeImBuf(och->ibufs_disp[f]); + } + } + MEM_freeN(och->ibufs_disp); + } + + if (och->ibufs_foam) { + for (i=och->start, f=0; i<=och->end; i++, f++) + { + if (och->ibufs_foam[f]) { + IMB_freeImBuf(och->ibufs_foam[f]); + } + } + MEM_freeN(och->ibufs_foam); + } + + if (och->ibufs_norm) { + for (i=och->start, f=0; i<=och->end; i++, f++) + { + if (och->ibufs_norm[f]) { + IMB_freeImBuf(och->ibufs_norm[f]); + } + } + MEM_freeN(och->ibufs_norm); + } + + if (och->time) + MEM_freeN(och->time); + MEM_freeN(och); +} + +void BKE_ocean_cache_eval_uv(struct OceanCache *och, struct OceanResult *ocr, int f, float u, float v) +{ + int res_x = och->resolution_x; + int res_y = och->resolution_y; + float result[4]; + + u = fmod(u, 1.0); + v = fmod(v, 1.0); + + if (u < 0) u += 1.0f; + if (v < 0) v += 1.0f; + + if (och->ibufs_disp[f]) { + ibuf_sample(och->ibufs_disp[f], u, v, (1.0/(float)res_x), (1.0/(float)res_y), result); + ocr->disp[0] = result[0]; + ocr->disp[1] = result[1]; + ocr->disp[2] = result[2]; + } + + if (och->ibufs_foam[f]) { + ibuf_sample(och->ibufs_foam[f], u, v, (1.0/(float)res_x), (1.0/(float)res_y), result); + ocr->foam = result[0]; + } + + if (och->ibufs_norm[f]) { + ibuf_sample(och->ibufs_norm[f], u, v, (1.0/(float)res_x), (1.0/(float)res_y), result); + ocr->normal[0] = result[0]; + ocr->normal[1] = result[1]; + ocr->normal[2] = result[2]; + } +} + +void BKE_ocean_cache_eval_ij(struct OceanCache *och, struct OceanResult *ocr, int f, int i, int j) +{ + int res_x = och->resolution_x; + int res_y = och->resolution_y; + + i = abs(i) % res_x; + j = abs(j) % res_y; + + if (och->ibufs_disp[f]) { + ocr->disp[0] = och->ibufs_disp[f]->rect_float[4*(res_x*j + i) + 0]; + ocr->disp[1] = och->ibufs_disp[f]->rect_float[4*(res_x*j + i) + 1]; + ocr->disp[2] = och->ibufs_disp[f]->rect_float[4*(res_x*j + i) + 2]; + } + + if (och->ibufs_foam[f]) { + ocr->foam = och->ibufs_foam[f]->rect_float[4*(res_x*j + i) + 0]; + } + + if (och->ibufs_norm[f]) { + ocr->normal[0] = och->ibufs_norm[f]->rect_float[4*(res_x*j + i) + 0]; + ocr->normal[1] = och->ibufs_norm[f]->rect_float[4*(res_x*j + i) + 1]; + ocr->normal[2] = och->ibufs_norm[f]->rect_float[4*(res_x*j + i) + 2]; + } +} + +struct OceanCache *BKE_init_ocean_cache(char *bakepath, int start, int end, float wave_scale, + float chop_amount, float foam_coverage, float foam_fade, int resolution) +{ + OceanCache *och = MEM_callocN(sizeof(OceanCache), "ocean cache data"); + + och->bakepath = bakepath; + och->start = start; + och->end = end; + och->duration = (end - start) + 1; + och->wave_scale = wave_scale; + och->chop_amount = chop_amount; + och->foam_coverage = foam_coverage; + och->foam_fade = foam_fade; + och->resolution_x = resolution*resolution; + och->resolution_y = resolution*resolution; + + och->ibufs_disp = MEM_callocN(sizeof(ImBuf *)*och->duration, "displacement imbuf pointer array"); + och->ibufs_foam = MEM_callocN(sizeof(ImBuf *)*och->duration, "foam imbuf pointer array"); + och->ibufs_norm = MEM_callocN(sizeof(ImBuf *)*och->duration, "normal imbuf pointer array"); + + och->time = NULL; + + return och; +} + +void BKE_simulate_ocean_cache(struct OceanCache *och, int frame) +{ + char string[FILE_MAX]; + int f = frame; + + /* ibufs array is zero based, but filenames are based on frame numbers */ + /* still need to clamp frame numbers to valid range of images on disk though */ + CLAMP(frame, och->start, och->end); + f = frame - och->start; // shift to 0 based + + /* if image is already loaded in mem, return */ + if (och->ibufs_disp[f] != NULL ) return; + + + cache_filename(string, och->bakepath, frame, CACHE_TYPE_DISPLACE); + och->ibufs_disp[f] = IMB_loadiffname(string, 0); + //if (och->ibufs_disp[f] == NULL) printf("error loading %s \n", string); + //else printf("loaded cache %s \n", string); + + cache_filename(string, och->bakepath, frame, CACHE_TYPE_FOAM); + och->ibufs_foam[f] = IMB_loadiffname(string, 0); + //if (och->ibufs_foam[f] == NULL) printf("error loading %s \n", string); + //else printf("loaded cache %s \n", string); + + cache_filename(string, och->bakepath, frame, CACHE_TYPE_NORMAL); + och->ibufs_norm[f] = IMB_loadiffname(string, 0); + //if (och->ibufs_norm[f] == NULL) printf("error loading %s \n", string); + //else printf("loaded cache %s \n", string); +} + + +void BKE_bake_ocean(struct Ocean *o, struct OceanCache *och, void (*update_cb)(void *, float progress, int *cancel), void *update_cb_data) +{ + int f, i=0, x, y, cancel=0; + float progress; + OceanResult ocr; + ImBuf *ibuf_foam, *ibuf_disp, *ibuf_normal; + float *prev_foam; + int res_x = och->resolution_x; + int res_y = och->resolution_y; + char string[FILE_MAX]; + + if (!o) return; + + prev_foam = MEM_callocN(res_x*res_y*sizeof(float), "previous frame foam bake data"); + + BLI_srand(0); + + for (f=och->start, i=0; f<=och->end; f++, i++) { + + /* create a new imbuf to store image for this frame */ + ibuf_foam = IMB_allocImBuf(res_x, res_y, 32, IB_rectfloat); + ibuf_disp = IMB_allocImBuf(res_x, res_y, 32, IB_rectfloat); + ibuf_normal = IMB_allocImBuf(res_x, res_y, 32, IB_rectfloat); + + ibuf_disp->profile = ibuf_foam->profile = ibuf_normal->profile = IB_PROFILE_LINEAR_RGB; + + BKE_simulate_ocean(o, och->time[i], och->wave_scale, och->chop_amount); + + /* add new foam */ + for (y=0; y < res_y; y++) { + for (x=0; x < res_x; x++) { + float r, pr=0.0, foam_result; + float neg_disp, neg_eplus; + + BKE_ocean_eval_ij(o, &ocr, x, y); + + normalize_v3(ocr.normal); + + /* foam */ + ocr.foam = BKE_ocean_jminus_to_foam(ocr.Jminus, och->foam_coverage); + + /* accumulate previous value for this cell */ + if (i>0) + pr = prev_foam[res_x*y + x]; + + r = BLI_frand(); // randomly reduce foam + + //pr = pr * och->foam_fade; // overall fade + + // remember ocean coord sys is Y up! + // break up the foam where height (Y) is low (wave valley), + // and X and Z displacement is greatest + + /* + vec[0] = ocr.disp[0]; + vec[1] = ocr.disp[2]; + hor_stretch = len_v2(vec); + CLAMP(hor_stretch, 0.0, 1.0); + */ + + neg_disp = ocr.disp[1]<0.0?1.0+ocr.disp[1]:1.0; + neg_disp = neg_disp<0.0?0.0:neg_disp; + + neg_eplus = ocr.Eplus[2]<0.0?1.0+ocr.Eplus[2]:1.0; + neg_eplus = neg_eplus<0.0?0.0:neg_eplus; + + //if (ocr.disp[1] < 0.0 || r > och->foam_fade) + // pr *= och->foam_fade; + + + //pr = pr * (1.0 - hor_stretch) * ocr.disp[1]; + //pr = pr * neg_disp * neg_eplus; + + if (pr < 1.0) pr *=pr; + + pr *= och->foam_fade * (0.75+neg_eplus*0.25); + + + foam_result = pr + ocr.foam; + + prev_foam[res_x*y + x] = foam_result; + + /* add to the image */ + ibuf_disp->rect_float[4*(res_x*y + x) + 0] = ocr.disp[0]; + ibuf_disp->rect_float[4*(res_x*y + x) + 1] = ocr.disp[1]; + ibuf_disp->rect_float[4*(res_x*y + x) + 2] = ocr.disp[2]; + ibuf_disp->rect_float[4*(res_x*y + x) + 3] = 1.0; + + if (o->_do_jacobian) { + ibuf_foam->rect_float[4*(res_x*y + x) + 0] = foam_result; + ibuf_foam->rect_float[4*(res_x*y + x) + 1] = foam_result; + ibuf_foam->rect_float[4*(res_x*y + x) + 2] = foam_result; + ibuf_foam->rect_float[4*(res_x*y + x) + 3] = 1.0; + } + + if (o->_do_normals) { + ibuf_normal->rect_float[4*(res_x*y + x) + 0] = ocr.normal[0]; + ibuf_normal->rect_float[4*(res_x*y + x) + 1] = ocr.normal[1]; + ibuf_normal->rect_float[4*(res_x*y + x) + 2] = ocr.normal[2]; + ibuf_normal->rect_float[4*(res_x*y + x) + 3] = 1.0; + } + + } + } + + /* write the images */ + cache_filename(string, och->bakepath, f, CACHE_TYPE_DISPLACE); + if(0 == BKE_write_ibuf(ibuf_disp, string, R_OPENEXR, R_OPENEXR_HALF, 2)) // 2 == ZIP exr codec + printf("Cannot save Displacement File Output to %s\n", string); + + if (o->_do_jacobian) { + cache_filename(string, och->bakepath, f, CACHE_TYPE_FOAM); + if(0 == BKE_write_ibuf(ibuf_foam, string, R_OPENEXR, R_OPENEXR_HALF, 2)) // 2 == ZIP exr codec + printf("Cannot save Foam File Output to %s\n", string); + } + + if (o->_do_normals) { + cache_filename(string, och->bakepath, f, CACHE_TYPE_NORMAL); + if(0 == BKE_write_ibuf(ibuf_normal, string, R_OPENEXR, R_OPENEXR_HALF, 2)) // 2 == ZIP exr codec + printf("Cannot save Normal File Output to %s\n", string); + } + + IMB_freeImBuf(ibuf_disp); + IMB_freeImBuf(ibuf_foam); + IMB_freeImBuf(ibuf_normal); + + progress = (f - och->start) / (float)och->duration; + + update_cb(update_cb_data, progress, &cancel); + + if (cancel) { + MEM_freeN(prev_foam); + return; + } + } + + MEM_freeN(prev_foam); + och->baked = 1; +} + +#else // WITH_OCEANSIM + +/* stub */ +typedef struct Ocean { +} Ocean; + + +float BKE_ocean_jminus_to_foam(float UNUSED(jminus), float UNUSED(coverage)) { + return 0.0f; +} + +void BKE_ocean_eval_uv(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr), float UNUSED(u),float UNUSED(v)) +{ +} + +// use catmullrom interpolation rather than linear +void BKE_ocean_eval_uv_catrom(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr), float UNUSED(u),float UNUSED(v)) +{ +} + +void BKE_ocean_eval_xz(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr), float UNUSED(x),float UNUSED(z)) +{ +} + +void BKE_ocean_eval_xz_catrom(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr), float UNUSED(x),float UNUSED(z)) +{ +} + +void BKE_ocean_eval_ij(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr), int UNUSED(i),int UNUSED(j)) +{ +} + +void BKE_simulate_ocean(struct Ocean *UNUSED(o), float UNUSED(t), float UNUSED(scale), float UNUSED(chop_amount)) +{ +} + +struct Ocean *BKE_add_ocean(void) +{ + Ocean *oc = MEM_callocN(sizeof(Ocean), "ocean sim data"); + + return oc; +} + +void BKE_init_ocean(struct Ocean* UNUSED(o), int UNUSED(M),int UNUSED(N), float UNUSED(Lx), float UNUSED(Lz), float UNUSED(V), float UNUSED(l), float UNUSED(A), float UNUSED(w), float UNUSED(damp), + float UNUSED(alignment), float UNUSED(depth), float UNUSED(time), short UNUSED(do_height_field), short UNUSED(do_chop), short UNUSED(do_normals), short UNUSED(do_jacobian), int UNUSED(seed)) +{ +} + +void BKE_free_ocean_data(struct Ocean *UNUSED(oc)) +{ +} + +void BKE_free_ocean(struct Ocean *oc) +{ + if(!oc) return; + MEM_freeN(oc); +} + + +/* ********* Baking/Caching ********* */ + + +void BKE_free_ocean_cache(struct OceanCache *och) +{ + if (!och) return; + + MEM_freeN(och); +} + +void BKE_ocean_cache_eval_uv(struct OceanCache *UNUSED(och), struct OceanResult *UNUSED(ocr), int UNUSED(f), float UNUSED(u), float UNUSED(v)) +{ +} + +void BKE_ocean_cache_eval_ij(struct OceanCache *UNUSED(och), struct OceanResult *UNUSED(ocr), int UNUSED(f), int UNUSED(i), int UNUSED(j)) +{ +} + +struct OceanCache *BKE_init_ocean_cache(char *UNUSED(bakepath), int UNUSED(start), int UNUSED(end), float UNUSED(wave_scale), + float UNUSED(chop_amount), float UNUSED(foam_coverage), float UNUSED(foam_fade), int UNUSED(resolution)) +{ + OceanCache *och = MEM_callocN(sizeof(OceanCache), "ocean cache data"); + + return och; +} + +void BKE_simulate_ocean_cache(struct OceanCache *UNUSED(och), int UNUSED(frame)) +{ +} + +void BKE_bake_ocean(struct Ocean *UNUSED(o), struct OceanCache *UNUSED(och), void (*update_cb)(void *, float progress, int *cancel), void *UNUSED(update_cb_data)) +{ + /* unused */ + (void)update_cb; +} +#endif // WITH_OCEANSIM diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index c80b2880d12..fcaeacd2eb4 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -60,6 +60,7 @@ #include "BKE_utildefines.h" #include "BKE_global.h" #include "BKE_main.h" +#include "BKE_ocean.h" #include "BKE_library.h" #include "BKE_image.h" @@ -71,6 +72,7 @@ #include "BKE_animsys.h" #include "BKE_colortools.h" + /* ------------------------------------------------------------------------- */ /* All support for plugin textures: */ @@ -546,6 +548,7 @@ void free_texture(Tex *tex) if(tex->env) BKE_free_envmap(tex->env); if(tex->pd) BKE_free_pointdensity(tex->pd); if(tex->vd) BKE_free_voxeldata(tex->vd); + if(tex->ot) BKE_free_oceantex(tex->ot); BKE_free_animdata((struct ID *)tex); BKE_previewimg_free(&tex->preview); @@ -628,6 +631,11 @@ void default_tex(Tex *tex) tex->vd->interp_type=TEX_VD_LINEAR; tex->vd->file_format=TEX_VD_SMOKE; } + + if (tex->ot) { + tex->ot->output = TEX_OCN_DISPLACEMENT; + tex->ot->object = NULL; + } pit = tex->plugin; if (pit) { varstr= pit->varstr; @@ -662,6 +670,10 @@ void tex_set_type(Tex *tex, int type) if (tex->env == NULL) tex->env = BKE_add_envmap(); break; + case TEX_OCEAN: + if (tex->ot == NULL) + tex->ot = BKE_add_oceantex(); + break; } tex->type = type; @@ -826,6 +838,7 @@ Tex *copy_texture(Tex *tex) if(texn->env) texn->env= BKE_copy_envmap(texn->env); if(texn->pd) texn->pd= BKE_copy_pointdensity(texn->pd); if(texn->vd) texn->vd= MEM_dupallocN(texn->vd); + if(texn->ot) texn->ot= BKE_copy_oceantex(texn->ot); if(tex->preview) texn->preview = BKE_previewimg_copy(tex->preview); if(tex->nodetree) { @@ -864,6 +877,9 @@ Tex *localize_texture(Tex *tex) if(texn->vd->dataset) texn->vd->dataset= MEM_dupallocN(texn->vd->dataset); } + if(texn->ot) { + texn->ot= BKE_copy_oceantex(tex->ot); + } texn->preview = NULL; @@ -1039,7 +1055,7 @@ void autotexname(Tex *tex) Main *bmain= G.main; char texstr[20][15]= {"None" , "Clouds" , "Wood", "Marble", "Magic" , "Blend", "Stucci", "Noise" , "Image", "Plugin", "EnvMap" , "Musgrave", - "Voronoi", "DistNoise", "Point Density", "Voxel Data", "", "", "", ""}; + "Voronoi", "DistNoise", "Point Density", "Voxel Data", "Ocean", "", "", ""}; Image *ima; char di[FILE_MAXDIR], fi[FILE_MAXFILE]; @@ -1469,6 +1485,7 @@ void BKE_free_pointdensity(PointDensity *pd) MEM_freeN(pd); } +/* ------------------------------------------------------------------------- */ void BKE_free_voxeldatadata(struct VoxelData *vd) { @@ -1513,6 +1530,31 @@ struct VoxelData *BKE_copy_voxeldata(struct VoxelData *vd) return vdn; } +/* ------------------------------------------------------------------------- */ + +struct OceanTex *BKE_add_oceantex(void) +{ + OceanTex *ot; + + ot= MEM_callocN(sizeof(struct OceanTex), "ocean texture"); + ot->output = TEX_OCN_DISPLACEMENT; + ot->object = NULL; + + return ot; +} + +struct OceanTex *BKE_copy_oceantex(struct OceanTex *ot) +{ + OceanTex *otn= MEM_dupallocN(ot); + + return otn; +} + +void BKE_free_oceantex(struct OceanTex *ot) +{ + MEM_freeN(ot); +} + /* ------------------------------------------------------------------------- */ int BKE_texture_dependsOnTime(const struct Tex *texture) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 3fd661a52da..9e3feedc5d9 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -120,6 +120,7 @@ #include "BKE_modifier.h" #include "BKE_multires.h" #include "BKE_node.h" // for tree type defines +#include "BKE_ocean.h" #include "BKE_object.h" #include "BKE_paint.h" #include "BKE_particle.h" @@ -3101,6 +3102,8 @@ static void lib_link_texture(FileData *fd, Main *main) if(tex->pd) tex->pd->object= newlibadr(fd, tex->id.lib, tex->pd->object); if(tex->vd) tex->vd->object= newlibadr(fd, tex->id.lib, tex->vd->object); + if(tex->ot) tex->ot->object= newlibadr(fd, tex->id.lib, tex->ot->object); + if(tex->nodetree) lib_link_ntree(fd, &tex->id, tex->nodetree); @@ -3152,6 +3155,8 @@ static void direct_link_texture(FileData *fd, Tex *tex) tex->vd= MEM_callocN(sizeof(VoxelData), "direct_link_texture VoxelData"); } + tex->ot= newdataadr(fd, tex->ot); + tex->nodetree= newdataadr(fd, tex->nodetree); if(tex->nodetree) direct_link_nodetree(fd, tex->nodetree); @@ -4368,6 +4373,12 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb) SWITCH_INT(mmd->bindcos[a]) } } + else if (md->type==eModifierType_Ocean) { + OceanModifierData *omd = (OceanModifierData*) md; + omd->oceancache = NULL; + omd->ocean = NULL; + omd->refresh = (MOD_OCEAN_REFRESH_ADD|MOD_OCEAN_REFRESH_RESET|MOD_OCEAN_REFRESH_SIM); + } else if (md->type==eModifierType_Warp) { WarpModifierData *tmd = (WarpModifierData *) md; @@ -11846,6 +11857,27 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } } } + + /* put compatibility code here until next subversion bump */ + if (main->versionfile < 255 || (main->versionfile == 255 && main->subversionfile < 3)) { + Object *ob; + Tex *tex; + + + /* ocean res is now squared, reset old ones - will be massive */ + for(ob = main->object.first; ob; ob = ob->id.next) { + ModifierData *md; + for(md= ob->modifiers.first; md; md= md->next) { + if (md->type == eModifierType_Ocean) { + OceanModifierData *omd = (OceanModifierData *)md; + omd->resolution = 7; + omd->oceancache = NULL; + } + } + } + } + + /* put compatibility code here until next subversion bump */ if (main->versionfile < 256) { bScreen *sc; diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 11a80d0d41a..2bb70ce20b5 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1815,6 +1815,7 @@ static void write_textures(WriteData *wd, ListBase *idbase) if(tex->pd->falloff_curve) write_curvemapping(wd, tex->pd->falloff_curve); } if(tex->type == TEX_VOXELDATA) writestruct(wd, DATA, "VoxelData", 1, tex->vd); + if(tex->type == TEX_OCEAN && tex->ot) writestruct(wd, DATA, "OceanTex", 1, tex->ot); /* nodetree is integral part of texture, no libdata */ if(tex->nodetree) { diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index a6e8d4a0a3a..185d8d43765 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -159,6 +159,7 @@ void OBJECT_OT_multires_external_save(struct wmOperatorType *ot); void OBJECT_OT_multires_external_pack(struct wmOperatorType *ot); void OBJECT_OT_meshdeform_bind(struct wmOperatorType *ot); void OBJECT_OT_explode_refresh(struct wmOperatorType *ot); +void OBJECT_OT_ocean_bake(struct wmOperatorType *ot); /* object_constraint.c */ void OBJECT_OT_constraint_add(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index ad2280baba2..af9e6592eb5 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -34,6 +34,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_anim_types.h" #include "DNA_curve_types.h" #include "DNA_key_types.h" #include "DNA_mesh_types.h" @@ -48,6 +49,7 @@ #include "BLI_editVert.h" #include "BLI_utildefines.h" +#include "BKE_animsys.h" #include "BKE_curve.h" #include "BKE_context.h" #include "BKE_depsgraph.h" @@ -63,6 +65,7 @@ #include "BKE_multires.h" #include "BKE_report.h" #include "BKE_object.h" +#include "BKE_ocean.h" #include "BKE_particle.h" #include "BKE_softbody.h" @@ -1404,3 +1407,219 @@ void OBJECT_OT_explode_refresh(wmOperatorType *ot) edit_modifier_properties(ot); } + +/****************** ocean bake operator *********************/ + +static int ocean_bake_poll(bContext *C) +{ + return edit_modifier_poll_generic(C, &RNA_OceanModifier, 0); +} + +/* copied from init_ocean_modifier, MOD_ocean.c */ +static void init_ocean_modifier_bake(struct Ocean *oc, struct OceanModifierData *omd) +{ + int do_heightfield, do_chop, do_normals, do_jacobian; + + if (!omd || !oc) return; + + do_heightfield = TRUE; + do_chop = (omd->chop_amount > 0); + do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS); + do_jacobian = (omd->flag & MOD_OCEAN_GENERATE_FOAM); + + BKE_init_ocean(oc, omd->resolution*omd->resolution, omd->resolution*omd->resolution, omd->spatial_size, omd->spatial_size, + omd->wind_velocity, omd->smallest_wave, 1.0, omd->wave_direction, omd->damp, omd->wave_alignment, + omd->depth, omd->time, + do_heightfield, do_chop, do_normals, do_jacobian, + omd->seed); +} + +typedef struct OceanBakeJob { + /* from wmJob */ + void *owner; + short *stop, *do_update; + float *progress; + int current_frame; + struct OceanCache *och; + struct Ocean *ocean; + struct OceanModifierData *omd; +} OceanBakeJob; + +static void oceanbake_free(void *customdata) +{ + OceanBakeJob *oj= customdata; + MEM_freeN(oj); +} + +/* called by oceanbake, only to check job 'stop' value */ +static int oceanbake_breakjob(void *UNUSED(customdata)) +{ + //OceanBakeJob *ob= (OceanBakeJob *)customdata; + //return *(ob->stop); + + /* this is not nice yet, need to make the jobs list template better + * for identifying/acting upon various different jobs */ + /* but for now we'll reuse the render break... */ + return (G.afbreek); +} + +/* called by oceanbake, wmJob sends notifier */ +static void oceanbake_update(void *customdata, float progress, int *cancel) +{ + OceanBakeJob *oj= customdata; + + if (oceanbake_breakjob(oj)) + *cancel = 1; + + *(oj->do_update)= 1; + *(oj->progress)= progress; +} + +static void oceanbake_startjob(void *customdata, short *stop, short *do_update, float *progress) +{ + OceanBakeJob *oj= customdata; + + oj->stop= stop; + oj->do_update = do_update; + oj->progress = progress; + + G.afbreek= 0; /* XXX shared with render - replace with job 'stop' switch */ + + BKE_bake_ocean(oj->ocean, oj->och, oceanbake_update, (void *)oj); + + *do_update= 1; + *stop = 0; +} + +static void oceanbake_endjob(void *customdata) +{ + OceanBakeJob *oj= customdata; + + if (oj->ocean) { + BKE_free_ocean(oj->ocean); + oj->ocean = NULL; + } + + oj->omd->oceancache = oj->och; + oj->omd->cached = TRUE; +} + +static int ocean_bake_exec(bContext *C, wmOperator *op) +{ + Object *ob = ED_object_active_context(C); + OceanModifierData *omd = (OceanModifierData *)edit_modifier_property_get(op, ob, eModifierType_Ocean); + Scene *scene = CTX_data_scene(C); + OceanCache *och; + struct Ocean *ocean; + int f, cfra, i=0; + int free= RNA_boolean_get(op->ptr, "free"); + + wmJob *steve; + OceanBakeJob *oj; + + if (!omd) + return OPERATOR_CANCELLED; + + if (free) { + omd->refresh |= MOD_OCEAN_REFRESH_CLEAR_CACHE; + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob); + return OPERATOR_FINISHED; + } + + och = BKE_init_ocean_cache(omd->cachepath, omd->bakestart, omd->bakeend, omd->wave_scale, + omd->chop_amount, omd->foam_coverage, omd->foam_fade, omd->resolution); + + och->time = MEM_mallocN(och->duration*sizeof(float), "foam bake time"); + + cfra = scene->r.cfra; + + /* precalculate time variable before baking */ + for (f=omd->bakestart; f<=omd->bakeend; f++) { + /* from physics_fluid.c: + + * XXX: This can't be used due to an anim sys optimisation that ignores recalc object animation, + * leaving it for the depgraph (this ignores object animation such as modifier properties though... :/ ) + * --> BKE_animsys_evaluate_all_animation(G.main, eval_time); + * This doesn't work with drivers: + * --> BKE_animsys_evaluate_animdata(&fsDomain->id, fsDomain->adt, eval_time, ADT_RECALC_ALL); + */ + + /* Modifying the global scene isn't nice, but we can do it in + * this part of the process before a threaded job is created */ + + //scene->r.cfra = f; + //ED_update_for_newframe(CTX_data_main(C), scene, CTX_wm_screen(C), 1); + + /* ok, this doesn't work with drivers, but is way faster. + * let's use this for now and hope nobody wants to drive the time value... */ + BKE_animsys_evaluate_animdata(scene, (ID *)ob, ob->adt, f, ADT_RECALC_ANIM); + + och->time[i] = omd->time; + i++; + } + + /* make a copy of ocean to use for baking - threadsafety */ + ocean = BKE_add_ocean(); + init_ocean_modifier_bake(ocean, omd); + + /* + BKE_bake_ocean(ocean, och); + + omd->oceancache = och; + omd->cached = TRUE; + + scene->r.cfra = cfra; + + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob); + */ + + /* job stuff */ + + scene->r.cfra = cfra; + + /* setup job */ + steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Ocean Simulation", WM_JOB_PROGRESS); + oj= MEM_callocN(sizeof(OceanBakeJob), "ocean bake job"); + oj->ocean = ocean; + oj->och = och; + oj->omd = omd; + + WM_jobs_customdata(steve, oj, oceanbake_free); + WM_jobs_timer(steve, 0.1, NC_OBJECT|ND_MODIFIER, NC_OBJECT|ND_MODIFIER); + WM_jobs_callbacks(steve, oceanbake_startjob, NULL, NULL, oceanbake_endjob); + + WM_jobs_start(CTX_wm_manager(C), steve); + + + + return OPERATOR_FINISHED; +} + +static int ocean_bake_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +{ + if (edit_modifier_invoke_properties(C, op)) + return ocean_bake_exec(C, op); + else + return OPERATOR_CANCELLED; +} + + +void OBJECT_OT_ocean_bake(wmOperatorType *ot) +{ + ot->name= "Bake Ocean"; + ot->description= "Bake an image sequence of ocean data"; + ot->idname= "OBJECT_OT_ocean_bake"; + + ot->poll= ocean_bake_poll; + ot->invoke= ocean_bake_invoke; + ot->exec= ocean_bake_exec; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + edit_modifier_properties(ot); + + RNA_def_boolean(ot->srna, "free", FALSE, "Free", "Free the bake, rather than generating it"); +} + diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 2df49570ee4..56c75331d48 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -142,6 +142,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_multires_external_pack); WM_operatortype_append(OBJECT_OT_meshdeform_bind); WM_operatortype_append(OBJECT_OT_explode_refresh); + WM_operatortype_append(OBJECT_OT_ocean_bake); WM_operatortype_append(OBJECT_OT_constraint_add); WM_operatortype_append(OBJECT_OT_constraint_add_with_targets); diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 20001ea6cb6..aec984cda34 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -75,6 +75,7 @@ typedef enum ModifierType { eModifierType_WeightVGProximity, eModifierType_EmptySlot, /* keep so DynamicPaint keep loading, can re-use later */ eModifierType_DynamicPaint, /* reserve slot */ + eModifierType_Ocean, NUM_MODIFIER_TYPES } ModifierType; @@ -750,6 +751,64 @@ typedef struct ScrewModifierData { #define MOD_SCREW_OBJECT_OFFSET (1<<2) // #define MOD_SCREW_OBJECT_ANGLE (1<<4) +typedef struct OceanModifierData { + ModifierData modifier; + + struct Ocean *ocean; + struct OceanCache *oceancache; + + int resolution; + int spatial_size; + + float wind_velocity; + + float damp; + float smallest_wave; + float depth; + + float wave_alignment; + float wave_direction; + float wave_scale; + + float chop_amount; + float foam_coverage; + float time; + + int seed; + int flag; + int output; + + int refresh; + + int bakestart; + int bakeend; + + char cachepath[240]; // FILE_MAX + int cached; + + int geometry_mode; + float size; + int repeat_x; + int repeat_y; + + float foam_fade; + +} OceanModifierData; + +#define MOD_OCEAN_GEOM_GENERATE 0 +#define MOD_OCEAN_GEOM_DISPLACE 1 +#define MOD_OCEAN_GEOM_SIM_ONLY 2 + +#define MOD_OCEAN_REFRESH_RESET 1 +#define MOD_OCEAN_REFRESH_SIM 2 +#define MOD_OCEAN_REFRESH_ADD 4 +#define MOD_OCEAN_REFRESH_CLEAR_CACHE 8 +#define MOD_OCEAN_REFRESH_TOPOLOGY 16 + +#define MOD_OCEAN_GENERATE_FOAM 1 +#define MOD_OCEAN_GENERATE_NORMALS 2 + + typedef struct WarpModifierData { ModifierData modifier; diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index 1ecca5a0b2a..ece99c8fc86 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -50,6 +50,7 @@ struct Tex; struct Image; struct PreviewImage; struct ImBuf; +struct Ocean; struct CurveMapping; typedef struct MTex { @@ -206,6 +207,15 @@ typedef struct VoxelData { } VoxelData; +typedef struct OceanTex { + struct Object *object; + char oceanmod[64]; + + int output; + int pad; + +} OceanTex; + typedef struct Tex { ID id; struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */ @@ -261,6 +271,7 @@ typedef struct Tex { struct PreviewImage * preview; struct PointDensity *pd; struct VoxelData *vd; + struct OceanTex *ot; char use_nodes; char pad[7]; @@ -318,6 +329,7 @@ typedef struct ColorMapping { #define TEX_DISTNOISE 13 #define TEX_POINTDENSITY 14 #define TEX_VOXELDATA 15 +#define TEX_OCEAN 16 /* musgrave stype */ #define TEX_MFRACTAL 0 @@ -588,6 +600,18 @@ typedef struct ColorMapping { #define TEX_VD_SMOKEHEAT 1 #define TEX_VD_SMOKEVEL 2 +/******************** Ocean *****************************/ +/* output */ +#define TEX_OCN_DISPLACEMENT 1 +#define TEX_OCN_FOAM 2 +#define TEX_OCN_JPLUS 3 +#define TEX_OCN_EMINUS 4 +#define TEX_OCN_EPLUS 5 + +/* flag */ +#define TEX_OCN_GENERATE_NORMALS 1 +#define TEX_OCN_XZ 2 + #ifdef __cplusplus } #endif diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index c9dadce0a5e..08e3d1a72a2 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -348,6 +348,9 @@ extern StructRNA RNA_NorController; extern StructRNA RNA_Object; extern StructRNA RNA_ObjectBase; extern StructRNA RNA_ObstacleFluidSettings; +extern StructRNA RNA_OceanModifier; +extern StructRNA RNA_OceanTexData; +extern StructRNA RNA_OceanTexture; extern StructRNA RNA_Operator; extern StructRNA RNA_OperatorFileListElement; extern StructRNA RNA_OperatorMousePath; diff --git a/source/blender/makesrna/SConscript b/source/blender/makesrna/SConscript index 769ec880a65..9eea6d83cb9 100644 --- a/source/blender/makesrna/SConscript +++ b/source/blender/makesrna/SConscript @@ -55,6 +55,9 @@ if env['WITH_BF_PYTHON']: if env['WITH_BF_COLLADA']: defs.append('WITH_COLLADA') +if env['WITH_BF_OCEANSIM']: + defs.append('WITH_OCEANSIM') + if env['OURPLATFORM'] == 'linux': cflags='-pthread' incs += ' ../../../extern/binreloc/include' diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 9bc532afa11..e50617f220c 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -206,6 +206,10 @@ if(WITH_FFTW3) add_definitions(-DWITH_FFTW3) endif() +if(WITH_OCEANSIM) + add_definitions(-DWITH_OCEANSIM) +endif() + if(WITH_SDL) add_definitions(-DWITH_SDL) endif() diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 32665bef065..aed5ba8840b 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -96,6 +96,7 @@ EnumPropertyItem modifier_type_items[] ={ {eModifierType_Softbody, "SOFT_BODY", ICON_MOD_SOFT, "Soft Body", ""}, {eModifierType_Surface, "SURFACE", ICON_MOD_PHYSICS, "Surface", ""}, {eModifierType_DynamicPaint, "DYNAMIC_PAINT", ICON_MOD_DYNAMICPAINT, "Dynamic Paint", ""}, + {eModifierType_Ocean, "OCEAN", ICON_MOD_WAVE, "Ocean", ""}, {0, NULL, 0, NULL, NULL}}; #ifdef RNA_RUNTIME @@ -186,6 +187,8 @@ static StructRNA* rna_Modifier_refine(struct PointerRNA *ptr) return &RNA_SolidifyModifier; case eModifierType_Screw: return &RNA_ScrewModifier; + case eModifierType_Ocean: + return &RNA_OceanModifier; case eModifierType_Warp: return &RNA_WarpModifier; case eModifierType_WeightVGEdit: @@ -649,6 +652,57 @@ static void rna_UVProjectModifier_num_projectors_set(PointerRNA *ptr, int value) md->projectors[a]= NULL; } +static int rna_OceanModifier_build_enabled_get(PointerRNA *UNUSED(ptr)) +{ + #ifdef WITH_OCEANSIM + return 1; + #else // WITH_OCEANSIM + return 0; + #endif // WITH_OCEANSIM +} + +static void rna_OceanModifier_init_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + OceanModifierData *omd= (OceanModifierData*)ptr->data; + + omd->refresh |= (MOD_OCEAN_REFRESH_RESET|MOD_OCEAN_REFRESH_SIM|MOD_OCEAN_REFRESH_CLEAR_CACHE); + + rna_Modifier_update(bmain, scene, ptr); +} + +static void rna_OceanModifier_sim_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + OceanModifierData *omd= (OceanModifierData*)ptr->data; + + omd->refresh |= MOD_OCEAN_REFRESH_SIM; + + rna_Modifier_update(bmain, scene, ptr); +} + +static void rna_OceanModifier_topology_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + OceanModifierData *omd= (OceanModifierData*)ptr->data; + + omd->refresh |= MOD_OCEAN_REFRESH_TOPOLOGY; + + rna_Modifier_update(bmain, scene, ptr); +} + +static void rna_OceanModifier_ocean_chop_set(PointerRNA *ptr, float value) +{ + OceanModifierData *omd= (OceanModifierData*)ptr->data; + float old_value = omd->chop_amount; + + omd->chop_amount = value; + + if ((old_value == 0.0 && value > 0.0) || + (old_value > 0.0 && value == 0.0)) + { + omd->refresh |= MOD_OCEAN_REFRESH_RESET; + omd->refresh |= MOD_OCEAN_REFRESH_CLEAR_CACHE; + } +} + static float rna_EdgeSplitModifier_split_angle_get(PointerRNA *ptr) { EdgeSplitModifierData *md= (EdgeSplitModifierData*)ptr->data; @@ -2809,6 +2863,181 @@ static void rna_def_modifier_weightvgproximity(BlenderRNA *brna) rna_def_modifier_weightvg_mask(brna, srna); } +static void rna_def_modifier_ocean(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + static EnumPropertyItem geometry_items[]= { + {MOD_OCEAN_GEOM_GENERATE, "GENERATE", 0, "Generate", "Generates ocean surface geometry at the specified resolution"}, + {MOD_OCEAN_GEOM_DISPLACE, "DISPLACE", 0, "Displace", "Displaces existing geometry according to simulation"}, + //{MOD_OCEAN_GEOM_SIM_ONLY, "SIM_ONLY", 0, "Sim Only", "Leaves geometry unchanged, but still runs simulation (to be used from texture)"}, + {0, NULL, 0, NULL, NULL}}; + + srna= RNA_def_struct(brna, "OceanModifier", "Modifier"); + RNA_def_struct_ui_text(srna, "Ocean Modifier", "Simulate an ocean surface"); + RNA_def_struct_sdna(srna, "OceanModifierData"); + RNA_def_struct_ui_icon(srna, ICON_MOD_FLUIDSIM); + + /* General check if OceanSim modifier code is enabled */ + prop= RNA_def_property(srna, "build_enabled", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_OceanModifier_build_enabled_get", NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Build Enabled", "True if the OceanSim modifier is enabled in this build"); + + prop= RNA_def_property(srna, "geometry_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "geometry_mode"); + RNA_def_property_enum_items(prop, geometry_items); + RNA_def_property_ui_text(prop, "Geometry", "Method of modifying geometry"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop= RNA_def_property(srna, "size", PROP_FLOAT, PROP_UNSIGNED); + RNA_def_property_float_sdna(prop, NULL, "size"); + RNA_def_property_ui_text(prop, "Size", ""); + RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 0); + RNA_def_property_update(prop, 0, "rna_OceanModifier_topology_update"); + + prop= RNA_def_property(srna, "repeat_x", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "repeat_x"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_range(prop, 1, 1024); + RNA_def_property_ui_range(prop, 1, 100, 1, 0); + RNA_def_property_ui_text(prop, "Repeat X", "Repetitions of the generated surface in X"); + RNA_def_property_update(prop, 0, "rna_OceanModifier_topology_update"); + + prop= RNA_def_property(srna, "repeat_y", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "repeat_y"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_range(prop, 1, 1024); + RNA_def_property_ui_range(prop, 1, 100, 1, 0); + RNA_def_property_ui_text(prop, "Repeat Y", "Repetitions of the generated surface in Y"); + RNA_def_property_update(prop, 0, "rna_OceanModifier_topology_update"); + + prop= RNA_def_property(srna, "generate_normals", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_OCEAN_GENERATE_NORMALS); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "Generate Normals", "Outputs normals for bump mapping - disabling can speed up performance if its not needed"); + RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); + + prop= RNA_def_property(srna, "generate_foam", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_OCEAN_GENERATE_FOAM); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "Generate Foam", "Generates foam mask as a vertex color channel"); + RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); + + prop= RNA_def_property(srna, "resolution", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "resolution"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_range(prop, 1, 1024); + RNA_def_property_ui_range(prop, 1, 32, 1, 0); + RNA_def_property_ui_text(prop, "Resolution", "Resolution of the generated surface"); + RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); + + prop= RNA_def_property(srna, "spatial_size", PROP_INT, PROP_DISTANCE); + RNA_def_property_int_sdna(prop, NULL, "spatial_size"); + RNA_def_property_ui_range(prop, 1, 512, 2, 0); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "Spatial Size", "Physical size of the simulation domain (m)"); + RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); + + prop= RNA_def_property(srna, "wind_velocity", PROP_FLOAT, PROP_VELOCITY); + RNA_def_property_float_sdna(prop, NULL, "wind_velocity"); + RNA_def_property_ui_text(prop, "Wind Velocity", "Wind speed (m/s)"); + RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); + + prop= RNA_def_property(srna, "damp", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "damp"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "Damping", "Damp reflected waves going in opposite direction to the wind"); + RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); + + prop= RNA_def_property(srna, "smallest_wave", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_sdna(prop, NULL, "smallest_wave"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_range(prop, 0.0, FLT_MAX); + RNA_def_property_ui_text(prop, "Smallest Wave", "Shortest allowed wavelength (m)"); + RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); + + prop= RNA_def_property(srna, "wave_alignment", PROP_FLOAT, PROP_UNSIGNED); + RNA_def_property_float_sdna(prop, NULL, "wave_alignment"); + RNA_def_property_range(prop, 0.0, 10.0); + RNA_def_property_ui_text(prop, "Wave Alignment", ""); + RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); + + prop= RNA_def_property(srna, "wave_direction", PROP_FLOAT, PROP_ANGLE); + RNA_def_property_float_sdna(prop, NULL, "wave_direction"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "Wave Direction", ""); + RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); + + prop= RNA_def_property(srna, "wave_scale", PROP_FLOAT, PROP_UNSIGNED); + RNA_def_property_float_sdna(prop, NULL, "wave_scale"); + RNA_def_property_ui_text(prop, "Wave Scale", ""); + RNA_def_property_update(prop, 0, "rna_OceanModifier_sim_update"); + + prop= RNA_def_property(srna, "depth", PROP_FLOAT, PROP_UNSIGNED); + RNA_def_property_float_sdna(prop, NULL, "depth"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "Depth", ""); + RNA_def_property_ui_range(prop, 0, 250, 1, 0); + RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); + + prop= RNA_def_property(srna, "foam_coverage", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "foam_coverage"); + RNA_def_property_ui_text(prop, "Foam Coverage", ""); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop= RNA_def_property(srna, "bake_foam_fade", PROP_FLOAT, PROP_UNSIGNED); + RNA_def_property_float_sdna(prop, NULL, "foam_fade"); + RNA_def_property_ui_text(prop, "Foam Fade", ""); + RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 0); + RNA_def_property_update(prop, 0, NULL); + + prop= RNA_def_property(srna, "choppiness", PROP_FLOAT, PROP_UNSIGNED); + RNA_def_property_float_sdna(prop, NULL, "chop_amount"); + RNA_def_property_ui_text(prop, "Choppiness", ""); + RNA_def_property_ui_range(prop, 0.0, 4.0, 3, 0); + RNA_def_property_float_funcs(prop, NULL, "rna_OceanModifier_ocean_chop_set", NULL); + RNA_def_property_update(prop, 0, "rna_OceanModifier_sim_update"); + + prop= RNA_def_property(srna, "time", PROP_FLOAT, PROP_UNSIGNED); + RNA_def_property_float_sdna(prop, NULL, "time"); + RNA_def_property_ui_text(prop, "Time", ""); + RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 0); + RNA_def_property_update(prop, 0, "rna_OceanModifier_sim_update"); + + prop= RNA_def_property(srna, "random_seed", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "seed"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "Random Seed", ""); + RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); + + prop= RNA_def_property(srna, "bake_start", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "bakestart"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "Bake Start", ""); + RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); + + prop= RNA_def_property(srna, "bake_end", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "bakeend"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "Bake End", ""); + RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); + + prop= RNA_def_property(srna, "is_cached", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "cached", 1); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Ocean is Cached", "Whether the ocean is useing cached data or simulating"); + + + prop= RNA_def_property(srna, "cachepath", PROP_STRING, PROP_DIRPATH); + RNA_def_property_string_sdna(prop, NULL, "cachepath"); + RNA_def_property_ui_text(prop, "Cache Path", "Path to a folder to store external baked images"); + //RNA_def_property_update(prop, 0, "rna_Modifier_update"); + // XXX how to update? +} + + void RNA_def_modifier(BlenderRNA *brna) { StructRNA *srna; @@ -2910,6 +3139,7 @@ void RNA_def_modifier(BlenderRNA *brna) rna_def_modifier_weightvgmix(brna); rna_def_modifier_weightvgproximity(brna); rna_def_modifier_dynamic_paint(brna); + rna_def_modifier_ocean(brna); } #endif diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c index aac4da9e6f6..249bdb4a366 100644 --- a/source/blender/makesrna/intern/rna_texture.c +++ b/source/blender/makesrna/intern/rna_texture.c @@ -73,6 +73,7 @@ EnumPropertyItem texture_type_items[] = { {TEX_VORONOI, "VORONOI", ICON_TEXTURE, "Voronoi", "Procedural - Create cell-like patterns based on Worley noise"}, {TEX_VOXELDATA, "VOXEL_DATA", ICON_TEXTURE, "Voxel Data", "Create a 3d texture based on volumetric data"}, {TEX_WOOD, "WOOD", ICON_TEXTURE, "Wood", "Procedural - Wave generated bands or rings, with optional noise"}, + {TEX_OCEAN, "OCEAN", ICON_TEXTURE, "Ocean", ""}, {0, NULL, 0, NULL, NULL}}; EnumPropertyItem blend_type_items[] = { @@ -145,6 +146,8 @@ static StructRNA *rna_Texture_refine(struct PointerRNA *ptr) return &RNA_VoxelDataTexture; case TEX_WOOD: return &RNA_WoodTexture; + case TEX_OCEAN: + return &RNA_OceanTexture; default: return &RNA_Texture; } @@ -435,6 +438,11 @@ static char *rna_VoxelData_path(PointerRNA *UNUSED(ptr)) return BLI_sprintfN("voxel_data"); } +static char *rna_OceanTex_path(PointerRNA *ptr) +{ + return BLI_sprintfN("ocean"); +} + #else static void rna_def_texmapping(BlenderRNA *brna) @@ -1860,6 +1868,49 @@ static void rna_def_texture_voxeldata(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Texture_voxeldata_update"); } +static void rna_def_texture_ocean(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + static EnumPropertyItem ocean_output_items[] = { + {TEX_OCN_DISPLACEMENT, "DISPLACEMENT", 0, "Displacement", "Outputs XYZ displacement in RGB channels"}, + //{TEX_OCN_NORMALS, "NORMALS", 0, "Normals", "Outputs wave normals"}, // these are in nor channel now + {TEX_OCN_FOAM, "FOAM", 0, "Foam", "Outputs Foam (wave overlap) amount in single channel"}, + {TEX_OCN_JPLUS, "JPLUS", 0, "Eigenvalues", "Positive Eigenvalues"}, + {TEX_OCN_EMINUS, "EMINUS", 0, "Eigenvectors (-)", "Negative Eigenvectors"}, + {TEX_OCN_EPLUS, "EPLUS", 0, "Eigenvectors (+)", "Positive Eigenvectors"}, + {0, NULL, 0, NULL, NULL}}; + + srna= RNA_def_struct(brna, "OceanTexData", NULL); + RNA_def_struct_sdna(srna, "OceanTex"); + RNA_def_struct_ui_text(srna, "Ocean", "Ocean Texture settings"); + RNA_def_struct_path_func(srna, "rna_OceanTex_path"); + + prop= RNA_def_property(srna, "output", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "output"); + RNA_def_property_enum_items(prop, ocean_output_items); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "Output", "The data that is output by the texture"); + RNA_def_property_update(prop, 0, "rna_Texture_update"); + + prop= RNA_def_property(srna, "ocean_object", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "object"); + RNA_def_property_ui_text(prop, "Modifier Object", "Object containing the ocean modifier"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_update(prop, 0, "rna_Texture_update"); + + srna= RNA_def_struct(brna, "OceanTexture", "Texture"); + RNA_def_struct_sdna(srna, "Tex"); + RNA_def_struct_ui_text(srna, "Ocean", "Settings for the Ocean texture"); + + prop= RNA_def_property(srna, "ocean", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "ot"); + RNA_def_property_struct_type(prop, "OceanTexData"); + RNA_def_property_ui_text(prop, "Ocean", "The ocean data associated with this texture"); + RNA_def_property_update(prop, 0, "rna_Texture_update"); +} + static void rna_def_texture(BlenderRNA *brna) { StructRNA *srna; @@ -1962,6 +2013,7 @@ static void rna_def_texture(BlenderRNA *brna) rna_def_texture_distorted_noise(brna); rna_def_texture_pointdensity(brna); rna_def_texture_voxeldata(brna); + rna_def_texture_ocean(brna); /* XXX add more types here .. */ RNA_api_texture(srna); diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt index e8ecc75ca60..4aedb4ae7a8 100644 --- a/source/blender/modifiers/CMakeLists.txt +++ b/source/blender/modifiers/CMakeLists.txt @@ -67,6 +67,7 @@ set(SRC intern/MOD_mirror.c intern/MOD_multires.c intern/MOD_none.c + intern/MOD_ocean.c intern/MOD_particleinstance.c intern/MOD_particlesystem.c intern/MOD_screw.c @@ -116,6 +117,10 @@ if(WITH_MOD_FLUID) add_definitions(-DWITH_MOD_FLUID) endif() +if(WITH_OCEANSIM) + add_definitions(-DWITH_OCEANSIM) +endif() + if(WITH_GAMEENGINE) # for MOD_navmesh.c add_definitions(-DWITH_GAMEENGINE) @@ -125,4 +130,8 @@ if(WITH_GAMEENGINE) ) endif() +if(WITH_OPENMP) + add_definitions(-DPARALLEL=1) +endif() + blender_add_lib(bf_modifiers "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h index 8ffb7803bb1..cc077694384 100644 --- a/source/blender/modifiers/MOD_modifiertypes.h +++ b/source/blender/modifiers/MOD_modifiertypes.h @@ -69,6 +69,7 @@ extern ModifierTypeInfo modifierType_Smoke; extern ModifierTypeInfo modifierType_ShapeKey; extern ModifierTypeInfo modifierType_Solidify; extern ModifierTypeInfo modifierType_Screw; +extern ModifierTypeInfo modifierType_Ocean; extern ModifierTypeInfo modifierType_Warp; extern ModifierTypeInfo modifierType_NavMesh; extern ModifierTypeInfo modifierType_WeightVGEdit; diff --git a/source/blender/modifiers/SConscript b/source/blender/modifiers/SConscript index 277ed2c3fb3..8273ab0d1fe 100644 --- a/source/blender/modifiers/SConscript +++ b/source/blender/modifiers/SConscript @@ -22,6 +22,9 @@ if env ['WITH_BF_DECIMATE']: if env['WITH_BF_FLUID']: defs.append('WITH_MOD_FLUID') +if env['WITH_BF_OCEANSIM']: + defs.append('WITH_OCEANSIM') + if env['WITH_BF_GAMEENGINE']: incs += ' #/extern/recastnavigation' defs.append('WITH_GAMEENGINE') diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c new file mode 100644 index 00000000000..f36d3674913 --- /dev/null +++ b/source/blender/modifiers/intern/MOD_ocean.c @@ -0,0 +1,561 @@ +/** + * $Id: MOD_ocean.c 28135 2010-04-11 23:20:03Z gsrb3d $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Matt Ebb + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_customdata_types.h" +#include "DNA_object_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_scene_types.h" + +#include "BKE_cdderivedmesh.h" +#include "BKE_modifier.h" +#include "BKE_ocean.h" +#include "BKE_utildefines.h" + +#include "BLI_math.h" +#include "BLI_math_inline.h" +#include "BLI_utildefines.h" + +#include "MOD_util.h" + +#ifdef WITH_OCEANSIM +static void init_cache_data(struct OceanModifierData *omd) +{ + omd->oceancache = BKE_init_ocean_cache(omd->cachepath, omd->bakestart, omd->bakeend, omd->wave_scale, + omd->chop_amount, omd->foam_coverage, omd->foam_fade, omd->resolution); +} + +static void clear_cache_data(struct OceanModifierData *omd) +{ + BKE_free_ocean_cache(omd->oceancache); + omd->oceancache = NULL; + omd->cached = FALSE; +} + +/* keep in sync with init_ocean_modifier_bake(), object_modifier.c */ +static void init_ocean_modifier(struct OceanModifierData *omd) +{ + int do_heightfield, do_chop, do_normals, do_jacobian; + + if (!omd || !omd->ocean) return; + + do_heightfield = TRUE; + do_chop = (omd->chop_amount > 0); + do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS); + do_jacobian = (omd->flag & MOD_OCEAN_GENERATE_FOAM); + + BKE_free_ocean_data(omd->ocean); + BKE_init_ocean(omd->ocean, omd->resolution*omd->resolution, omd->resolution*omd->resolution, omd->spatial_size, omd->spatial_size, + omd->wind_velocity, omd->smallest_wave, 1.0, omd->wave_direction, omd->damp, omd->wave_alignment, + omd->depth, omd->time, + do_heightfield, do_chop, do_normals, do_jacobian, + omd->seed); +} + +static void simulate_ocean_modifier(struct OceanModifierData *omd) +{ + if (!omd || !omd->ocean) return; + + BKE_simulate_ocean(omd->ocean, omd->time, omd->wave_scale, omd->chop_amount); +} +#endif // WITH_OCEANSIM + + + +/* Modifier Code */ + +static void initData(ModifierData *md) +{ +#ifdef WITH_OCEANSIM + OceanModifierData *omd = (OceanModifierData*) md; + + omd->resolution = 7; + omd->spatial_size = 50; + + omd->wave_alignment = 0.0; + omd->wind_velocity = 30.0; + + omd->damp = 0.5; + omd->smallest_wave = 0.01; + omd->wave_direction= 0.0; + omd->depth = 200.0; + + omd->wave_scale = 1.0; + + omd->chop_amount = 1.0; + + omd->foam_coverage = 0.0; + + omd->seed = 0; + omd->time = 1.0; + + omd->refresh = 0; + + omd->size = 1.0; + omd->repeat_x = 1; + omd->repeat_y = 1; + + strcpy(omd->cachepath, "//ocean_cache/"); + + omd->cached = 0; + omd->bakestart = 1; + omd->bakeend = 250; + omd->oceancache = NULL; + omd->foam_fade = 0.98; + + omd->ocean = BKE_add_ocean(); + init_ocean_modifier(omd); + simulate_ocean_modifier(omd); +#else // WITH_OCEANSIM + /* unused */ + (void)md; +#endif // WITH_OCEANSIM +} + +static void freeData(ModifierData *md) +{ +#ifdef WITH_OCEANSIM + OceanModifierData *omd = (OceanModifierData*) md; + + BKE_free_ocean(omd->ocean); + if (omd->oceancache) + BKE_free_ocean_cache(omd->oceancache); +#else // WITH_OCEANSIM + /* unused */ + (void)md; +#endif // WITH_OCEANSIM +} + +static void copyData(ModifierData *md, ModifierData *target) +{ +#ifdef WITH_OCEANSIM + OceanModifierData *omd = (OceanModifierData*) md; + OceanModifierData *tomd = (OceanModifierData*) target; + + tomd->resolution = omd->resolution; + tomd->spatial_size = omd->spatial_size; + + tomd->wind_velocity = omd->wind_velocity; + + tomd->damp = omd->damp; + tomd->smallest_wave = omd->smallest_wave; + tomd->depth = omd->depth; + + tomd->wave_alignment = omd->wave_alignment; + tomd->wave_direction = omd->wave_direction; + tomd->wave_scale = omd->wave_scale; + + tomd->chop_amount = omd->chop_amount; + tomd->foam_coverage = omd->foam_coverage; + tomd->time = omd->time; + + tomd->seed = omd->seed; + tomd->flag = omd->flag; + tomd->output = omd->output; + + tomd->refresh = 0; + + + tomd->size = omd->size; + tomd->repeat_x = omd->repeat_x; + tomd->repeat_y = omd->repeat_y; + + /* XXX todo: copy cache runtime too */ + tomd->cached = 0; + tomd->bakestart = omd->bakestart; + tomd->bakeend = omd->bakeend; + tomd->oceancache = NULL; + + tomd->ocean = BKE_add_ocean(); + init_ocean_modifier(tomd); + simulate_ocean_modifier(tomd); +#else // WITH_OCEANSIM + /* unused */ + (void)md; + (void)target; +#endif // WITH_OCEANSIM +} + +#ifdef WITH_OCEANSIM +static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md) +{ + OceanModifierData *omd = (OceanModifierData *)md; + CustomDataMask dataMask = 0; + + if (omd->flag & MOD_OCEAN_GENERATE_FOAM) + dataMask |= CD_MASK_MCOL; + + return dataMask; +} +#else // WITH_OCEANSIM +static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md) +{ + /* unused */ + (void)md; + return 0; +} +#endif // WITH_OCEANSIM + +#if 0 +static void dm_get_bounds(DerivedMesh *dm, float *sx, float *sy, float *ox, float *oy) +{ + /* get bounding box of underlying dm */ + int v, totvert=dm->getNumVerts(dm); + float min[3], max[3], delta[3]; + + MVert *mvert = dm->getVertDataArray(dm,0); + + copy_v3_v3(min, mvert->co); + copy_v3_v3(max, mvert->co); + + for(v=1; vco[0]); + min[1]=MIN2(min[1],mvert->co[1]); + min[2]=MIN2(min[2],mvert->co[2]); + + max[0]=MAX2(max[0],mvert->co[0]); + max[1]=MAX2(max[1],mvert->co[1]); + max[2]=MAX2(max[2],mvert->co[2]); + } + + sub_v3_v3v3(delta, max, min); + + *sx = delta[0]; + *sy = delta[1]; + + *ox = min[0]; + *oy = min[1]; +} +#endif + +#ifdef WITH_OCEANSIM +MINLINE float ocean_co(OceanModifierData *omd, float v) +{ + //float scale = 1.0 / (omd->size * omd->spatial_size); + //*v = (*v * scale) + 0.5; + + return (v / (omd->size * omd->spatial_size)) + 0.5; +} + +#define OMP_MIN_RES 18 +static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd) +{ + DerivedMesh *result; + + MVert *mv; + MFace *mf; + MTFace *tf; + + int cdlayer; + + const int rx = omd->resolution*omd->resolution; + const int ry = omd->resolution*omd->resolution; + const int res_x = rx * omd->repeat_x; + const int res_y = ry * omd->repeat_y; + + const int num_verts = (res_x + 1) * (res_y + 1); + const int num_edges = (res_x * res_y * 2) + res_x + res_y; + const int num_faces = res_x * res_y; + + float sx = omd->size * omd->spatial_size; + float sy = omd->size * omd->spatial_size; + const float ox = -sx / 2.0; + const float oy = -sy / 2.0; + + float ix, iy; + + int x, y; + + sx /= rx; + sy /= ry; + + result = CDDM_new(num_verts, num_edges, num_faces); + + mv = CDDM_get_verts(result); + mf = CDDM_get_faces(result); + + /* create vertices */ + #pragma omp parallel for private(x, y) if (rx > OMP_MIN_RES) + for (y=0; y < res_y+1; y++) { + for (x=0; x < res_x+1; x++) { + const int i = y*(res_x+1) + x; + mv[i].co[0] = ox + (x * sx); + mv[i].co[1] = oy + (y * sy); + mv[i].co[2] = 0; + } + } + + /* create faces */ + #pragma omp parallel for private(x, y) if (rx > OMP_MIN_RES) + for (y=0; y < res_y; y++) { + for (x=0; x < res_x; x++) { + const int fi = y*res_x + x; + const int vi = y*(res_x+1) + x; + mf[fi].v1 = vi; + mf[fi].v2 = vi + 1; + mf[fi].v3 = vi + 1 + res_x+1; + mf[fi].v4 = vi + res_x+1; + + mf[fi].flag |= ME_SMOOTH; + } + } + + CDDM_calc_edges(result); + + /* add uvs */ + cdlayer= CustomData_number_of_layers(&result->faceData, CD_MTFACE); + if(cdlayer >= MAX_MTFACE) + return result; + CustomData_add_layer(&result->faceData, CD_MTFACE, CD_CALLOC, NULL, num_faces); + tf = CustomData_get_layer(&result->faceData, CD_MTFACE); + + ix = 1.0 / rx; + iy = 1.0 / ry; + #pragma omp parallel for private(x, y) if (rx > OMP_MIN_RES) + for (y=0; y < res_y; y++) { + for (x=0; x < res_x; x++) { + const int i = y*res_x + x; + tf[i].uv[0][0] = x * ix; + tf[i].uv[0][1] = y * iy; + + tf[i].uv[1][0] = (x+1) * ix; + tf[i].uv[1][1] = y * iy; + + tf[i].uv[2][0] = (x+1) * ix; + tf[i].uv[2][1] = (y+1) * iy; + + tf[i].uv[3][0] = x * ix; + tf[i].uv[3][1] = (y+1) * iy; + } + } + + return result; +} + +static DerivedMesh *doOcean(ModifierData *md, Object *UNUSED(ob), + DerivedMesh *derivedData, + int UNUSED(useRenderParams)) +{ + OceanModifierData *omd = (OceanModifierData*) md; + + DerivedMesh *dm=NULL; + OceanResult ocr; + + MVert *mv; + MFace *mf; + + int cdlayer; + + int i, j; + + int num_verts; + int num_faces; + + int cfra; + + /* update modifier */ + if (omd->refresh & MOD_OCEAN_REFRESH_ADD) + omd->ocean = BKE_add_ocean(); + if (omd->refresh & MOD_OCEAN_REFRESH_RESET) + init_ocean_modifier(omd); + if (omd->refresh & MOD_OCEAN_REFRESH_CLEAR_CACHE) + clear_cache_data(omd); + + omd->refresh = 0; + + /* do ocean simulation */ + if (omd->cached == TRUE) { + if (!omd->oceancache) init_cache_data(omd); + BKE_simulate_ocean_cache(omd->oceancache, md->scene->r.cfra); + } else { + simulate_ocean_modifier(omd); + } + + if (omd->geometry_mode == MOD_OCEAN_GEOM_GENERATE) + dm = generate_ocean_geometry(omd); + else if (omd->geometry_mode == MOD_OCEAN_GEOM_DISPLACE) { + dm = CDDM_copy(derivedData); + } + + cfra = md->scene->r.cfra; + CLAMP(cfra, omd->bakestart, omd->bakeend); + cfra -= omd->bakestart; // shift to 0 based + + num_verts = dm->getNumVerts(dm); + num_faces = dm->getNumFaces(dm); + + /* add vcols before displacement - allows lookup based on position */ + + if (omd->flag & MOD_OCEAN_GENERATE_FOAM) { + MCol *mc; + float foam; + char cf; + + float u=0.0, v=0.0; + + cdlayer= CustomData_number_of_layers(&dm->faceData, CD_MCOL); + if(cdlayer >= MAX_MCOL) + return dm; + + CustomData_add_layer(&dm->faceData, CD_MCOL, CD_CALLOC, NULL, num_faces); + + mc = dm->getFaceDataArray(dm, CD_MCOL); + mv = dm->getVertArray(dm); + mf = dm->getFaceArray(dm); + + for (i = 0; i < num_faces; i++, mf++) { + for (j=0; j<4; j++) { + + if (j == 3 && !mf->v4) continue; + + switch(j) { + case 0: + u = ocean_co(omd, mv[mf->v1].co[0]); + v = ocean_co(omd, mv[mf->v1].co[1]); + break; + case 1: + u = ocean_co(omd, mv[mf->v2].co[0]); + v = ocean_co(omd, mv[mf->v2].co[1]); + break; + case 2: + u = ocean_co(omd, mv[mf->v3].co[0]); + v = ocean_co(omd, mv[mf->v3].co[1]); + break; + case 3: + u = ocean_co(omd, mv[mf->v4].co[0]); + v = ocean_co(omd, mv[mf->v4].co[1]); + + break; + } + + if (omd->oceancache && omd->cached==TRUE) { + BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v); + foam = ocr.foam; + CLAMP(foam, 0.0, 1.0); + } else { + BKE_ocean_eval_uv(omd->ocean, &ocr, u, v); + foam = BKE_ocean_jminus_to_foam(ocr.Jminus, omd->foam_coverage); + } + + cf = (char)(foam*255); + mc[i*4 + j].r = mc[i*4 + j].g = mc[i*4 + j].b = cf; + mc[i*4 + j].a = 255; + } + } + } + + + /* displace the geometry */ + + mv = dm->getVertArray(dm); + + //#pragma omp parallel for private(i, ocr) if (omd->resolution > OMP_MIN_RES) + for (i=0; i< num_verts; i++) { + const float u = ocean_co(omd, mv[i].co[0]); + const float v = ocean_co(omd, mv[i].co[1]); + + if (omd->oceancache && omd->cached==TRUE) + BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v); + else + BKE_ocean_eval_uv(omd->ocean, &ocr, u, v); + + mv[i].co[2] += ocr.disp[1]; + + if (omd->chop_amount > 0.0) { + mv[i].co[0] += ocr.disp[0]; + mv[i].co[1] += ocr.disp[2]; + } + } + + + return dm; +} +#else // WITH_OCEANSIM +static DerivedMesh *doOcean(ModifierData *md, Object *UNUSED(ob), + DerivedMesh *derivedData, + int UNUSED(useRenderParams)) +{ + /* unused */ + (void)md; + return derivedData; +} +#endif // WITH_OCEANSIM + +static DerivedMesh *applyModifier(ModifierData *md, Object *ob, + DerivedMesh *derivedData, + int UNUSED(useRenderParams), + int UNUSED(isFinalCalc)) +{ + DerivedMesh *result; + + result = doOcean(md, ob, derivedData, 0); + + if(result != derivedData) + CDDM_calc_normals(result); + + return result; +} + +static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob, + struct EditMesh *UNUSED(editData), + DerivedMesh *derivedData) +{ + return applyModifier(md, ob, derivedData, 0, 1); +} + + + +ModifierTypeInfo modifierType_Ocean = { + /* name */ "Ocean", + /* structName */ "OceanModifierData", + /* structSize */ sizeof(OceanModifierData), + /* type */ eModifierTypeType_Constructive, + /* flags */ eModifierTypeFlag_AcceptsMesh + | eModifierTypeFlag_SupportsEditmode + | eModifierTypeFlag_EnableInEditmode, + + /* copyData */ copyData, + /* deformMatrices */ 0, + /* deformVerts */ 0, + /* deformVertsEM */ 0, + /* deformMatricesEM */ 0, + /* applyModifier */ applyModifier, + /* applyModifierEM */ applyModifierEM, + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ freeData, + /* isDisabled */ 0, + /* updateDepgraph */ 0, + /* dependsOnTime */ 0, + /* dependsOnNormals */ 0, + /* foreachObjectLink */ 0, + /* foreachIDLink */ 0, +}; diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c index 38abb96aa7c..01c7f31b67a 100644 --- a/source/blender/modifiers/intern/MOD_util.c +++ b/source/blender/modifiers/intern/MOD_util.c @@ -260,6 +260,7 @@ void modifier_type_init(ModifierTypeInfo *types[]) INIT_TYPE(Collision); INIT_TYPE(Boolean); INIT_TYPE(MeshDeform); + INIT_TYPE(Ocean); INIT_TYPE(ParticleSystem); INIT_TYPE(ParticleInstance); INIT_TYPE(Explode); diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt index 763cd3780fb..c7b27c3cd7e 100644 --- a/source/blender/render/CMakeLists.txt +++ b/source/blender/render/CMakeLists.txt @@ -74,6 +74,7 @@ set(SRC intern/source/sss.c intern/source/strand.c intern/source/sunsky.c + intern/source/texture_ocean.c intern/source/volume_precache.c intern/source/volumetric.c intern/source/voxeldata.c @@ -104,6 +105,7 @@ set(SRC intern/include/strand.h intern/include/sunsky.h intern/include/texture.h + intern/include/texture_ocean.h intern/include/volume_precache.h intern/include/volumetric.h intern/include/voxeldata.h diff --git a/source/blender/render/intern/include/texture_ocean.h b/source/blender/render/intern/include/texture_ocean.h new file mode 100644 index 00000000000..b0a0647d115 --- /dev/null +++ b/source/blender/render/intern/include/texture_ocean.h @@ -0,0 +1,28 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributors: Matt Ebb + * + * ***** END GPL LICENSE BLOCK ***** + */ + +void prepare_ocean_tex_modifier(struct OceanTex *ot); + +int ocean_texture(struct Tex *tex, float *texvec, struct TexResult *texres); diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c index afc52f7c92a..bd323a5b2d3 100644 --- a/source/blender/render/intern/source/render_texture.c +++ b/source/blender/render/intern/source/render_texture.c @@ -79,6 +79,7 @@ #include "rendercore.h" #include "shading.h" #include "texture.h" +#include "texture_ocean.h" #include "renderdatabase.h" /* needed for UV */ @@ -1264,7 +1265,9 @@ static int multitex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, case TEX_VOXELDATA: retval= voxeldatatex(tex, texvec, texres); break; - + case TEX_OCEAN: + retval= ocean_texture(tex, texvec, texres); + break; } if (tex->flag & TEX_COLORBAND) { @@ -2193,6 +2196,12 @@ void do_material_tex(ShadeInput *shi, Render *re) use_ntap_bump = 0; use_compat_bump = 1; } + + /* case ocean */ + if(tex->type == TEX_OCEAN) { + use_ntap_bump = 0; + use_compat_bump = 0; + } /* which coords */ if(mtex->texco==TEXCO_ORCO) { diff --git a/source/blender/render/intern/source/texture_ocean.c b/source/blender/render/intern/source/texture_ocean.c new file mode 100644 index 00000000000..c9d84b23e33 --- /dev/null +++ b/source/blender/render/intern/source/texture_ocean.c @@ -0,0 +1,162 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributors: Matt Ebb + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_texture_types.h" + +#include "BKE_global.h" /* XXX */ + +#include "BKE_modifier.h" +#include "BKE_ocean.h" +#include "BKE_utildefines.h" + +#include "render_types.h" +#include "RE_shader_ext.h" + +#include "texture.h" + + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ +/* only to be used here in this file, it's for speed */ +extern struct Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + + + + +/* ***** actual texture sampling ***** */ +int ocean_texture(Tex *tex, float *texvec, TexResult *texres) +{ + int retval = TEX_INT; + OceanTex *ot= tex->ot; + OceanResult or; + const float u = 0.5+0.5*texvec[0]; + const float v = 0.5+0.5*texvec[1]; + float foam; + int cfra = R.r.cfra; + int normals=0; + ModifierData *md; + + texres->tin = 0.0f; + + if (!ot || !ot->object || !ot->object->modifiers.first) + return 0; + + if ((md = (ModifierData *)modifiers_findByType(ot->object, eModifierType_Ocean))) { + OceanModifierData *omd = (OceanModifierData *)md; + + if (!omd->ocean) + return 0; + + normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS); + + if (omd->oceancache && omd->cached==TRUE) { + + CLAMP(cfra, omd->bakestart, omd->bakeend); + cfra -= omd->bakestart; // shift to 0 based + + BKE_ocean_cache_eval_uv(omd->oceancache, &or, cfra, u, v); + + } else { // non-cached + + if (G.rendering) + BKE_ocean_eval_uv_catrom(omd->ocean, &or, u, v); + else + BKE_ocean_eval_uv(omd->ocean, &or, u, v); + + or.foam = BKE_ocean_jminus_to_foam(or.Jminus, omd->foam_coverage); + } + } + + + switch (ot->output) { + case TEX_OCN_DISPLACEMENT: + /* XYZ displacement */ + texres->tr = 0.5 + 0.5 * or.disp[0]; + texres->tg = 0.5 + 0.5 * or.disp[2]; + texres->tb = 0.5 + 0.5 * or.disp[1]; + + texres->tr = MAX2(0.0, texres->tr); + texres->tg = MAX2(0.0, texres->tg); + texres->tb = MAX2(0.0, texres->tb); + + BRICONTRGB; + + retval = TEX_RGB; + break; + + case TEX_OCN_EMINUS: + /* -ve eigenvectors ? */ + texres->tr = or.Eminus[0]; + texres->tg = or.Eminus[2]; + texres->tb = or.Eminus[1]; + retval = TEX_RGB; + break; + + case TEX_OCN_EPLUS: + /* -ve eigenvectors ? */ + texres->tr = or.Eplus[0]; + texres->tg = or.Eplus[2]; + texres->tb = or.Eplus[1]; + retval = TEX_RGB; + break; + + case TEX_OCN_JPLUS: + texres->tin = or.Jplus; + retval = TEX_INT; + case TEX_OCN_FOAM: + + texres->tin = or.foam; + + BRICONT; + + retval = TEX_INT; + break; + } + + /* if normals needed */ + + if (texres->nor && normals) { + + texres->nor[0] = or.normal[0]; + texres->nor[1] = or.normal[2]; + texres->nor[2] = or.normal[1]; + + normalize_v3(texres->nor); + retval |= TEX_NOR; + } + + texres->ta = 1.0; + + return retval; +} + -- cgit v1.2.3