Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt6
-rw-r--r--SConstruct5
-rw-r--r--build_files/scons/tools/btools.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_modifier.py68
-rw-r--r--release/scripts/startup/bl_ui/properties_texture.py16
-rw-r--r--source/blender/blenkernel/BKE_ocean.h108
-rw-r--r--source/blender/blenkernel/BKE_texture.h5
-rw-r--r--source/blender/blenkernel/CMakeLists.txt11
-rw-r--r--source/blender/blenkernel/SConscript7
-rw-r--r--source/blender/blenkernel/intern/ocean.c1407
-rw-r--r--source/blender/blenkernel/intern/texture.c44
-rw-r--r--source/blender/blenloader/intern/readfile.c32
-rw-r--r--source/blender/blenloader/intern/writefile.c1
-rw-r--r--source/blender/editors/object/object_intern.h1
-rw-r--r--source/blender/editors/object/object_modifier.c219
-rw-r--r--source/blender/editors/object/object_ops.c1
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h59
-rw-r--r--source/blender/makesdna/DNA_texture_types.h24
-rw-r--r--source/blender/makesrna/RNA_access.h3
-rw-r--r--source/blender/makesrna/SConscript3
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt4
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c230
-rw-r--r--source/blender/makesrna/intern/rna_texture.c52
-rw-r--r--source/blender/modifiers/CMakeLists.txt9
-rw-r--r--source/blender/modifiers/MOD_modifiertypes.h1
-rw-r--r--source/blender/modifiers/SConscript3
-rw-r--r--source/blender/modifiers/intern/MOD_ocean.c561
-rw-r--r--source/blender/modifiers/intern/MOD_util.c1
-rw-r--r--source/blender/render/CMakeLists.txt2
-rw-r--r--source/blender/render/intern/include/texture_ocean.h28
-rw-r--r--source/blender/render/intern/source/render_texture.c11
-rw-r--r--source/blender/render/intern/source/texture_ocean.c162
32 files changed, 3084 insertions, 2 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 36ef022f3c1..40239a16f02 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -171,6 +171,7 @@ option(WITH_MOD_DECIMATE "Enable Decimate Modifier" ON)
option(WITH_MOD_BOOLEAN "Enable Boolean Modifier" ON)
option(WITH_MOD_CLOTH_ELTOPO "Enable Experemental cloth solver" OFF)
mark_as_advanced(WITH_MOD_CLOTH_ELTOPO)
+option(WITH_OCEANSIM "Enable Ocean Modifier" OFF)
# Image format support
option(WITH_IMAGE_OPENEXR "Enable OpenEXR Support (http://www.openexr.com)" ON)
@@ -285,6 +286,10 @@ if(WITH_CODEC_QUICKTIME AND MINGW)
"line if youre a developer who wants to add support.")
endif()
+if(NOT WITH_FFTW3 AND WITH_OCEANSIM)
+ message(FATAL_ERROR "WITH_OCEANSIM requires WITH_FFTW3 to be ON")
+endif()
+
# may as well build python module without a UI
if(WITH_PYTHON_MODULE)
set(WITH_HEADLESS ON)
@@ -1562,6 +1567,7 @@ if(FIRST_RUN)
info_cfg_option(WITH_MOD_BOOLEAN)
info_cfg_option(WITH_MOD_DECIMATE)
info_cfg_option(WITH_MOD_FLUID)
+ info_cfg_option(WITH_OCEANSIM)
info_cfg_text("")
diff --git a/SConstruct b/SConstruct
index 161bbbc0378..57da56872aa 100644
--- a/SConstruct
+++ b/SConstruct
@@ -254,6 +254,7 @@ if 'blenderlite' in B.targets:
target_env_defs['WITH_BF_BINRELOC'] = False
target_env_defs['BF_BUILDINFO'] = False
target_env_defs['WITH_BF_FLUID'] = False
+ target_env_defs['WITH_BF_OCEANSIM'] = False
target_env_defs['WITH_BF_DECIMATE'] = False
target_env_defs['WITH_BF_BOOLEAN'] = False
target_env_defs['WITH_BF_PYTHON'] = False
@@ -329,6 +330,10 @@ if 'blendernogame' in B.targets:
if env['WITH_BF_FLUID'] == 1:
env['CPPFLAGS'].append('-DWITH_MOD_FLUID')
+# build with ocean sim?
+if env['WITH_BF_OCEANSIM'] == 1:
+ env['CPPFLAGS'].append('-DWITH_MOD_OCEANSIM')
+
if btools.ENDIAN == "big":
env['CPPFLAGS'].append('-D__BIG_ENDIAN__')
diff --git a/build_files/scons/tools/btools.py b/build_files/scons/tools/btools.py
index 417bbcc48ba..856231e3c84 100644
--- a/build_files/scons/tools/btools.py
+++ b/build_files/scons/tools/btools.py
@@ -152,6 +152,7 @@ def validate_arguments(args, bc):
'WITH_BF_FLUID',
'WITH_BF_DECIMATE',
'WITH_BF_BOOLEAN',
+ 'WITH_BF_OCEANSIM',
'WITH_BF_CXX_GUARDEDALLOC',
'WITH_BF_JEMALLOC', 'WITH_BF_STATICJEMALLOC', 'BF_JEMALLOC', 'BF_JEMALLOC_INC', 'BF_JEMALLOC_LIBPATH', 'BF_JEMALLOC_LIB', 'BF_JEMALLOC_LIB_STATIC',
'BUILDBOT_BRANCH',
@@ -259,6 +260,7 @@ def read_opts(env, cfg, args):
(BoolVariable('WITH_BF_FLUID', 'Build with Fluid simulation (Elbeem)', True)),
(BoolVariable('WITH_BF_DECIMATE', 'Build with decimate modifier', True)),
(BoolVariable('WITH_BF_BOOLEAN', 'Build with boolean modifier', True)),
+ (BoolVariable('WITH_BF_OCEANSIM', 'Build with ocean simulation', False)),
('BF_PROFILE_FLAGS', 'Profiling compiler flags', ''),
(BoolVariable('WITH_BF_OPENAL', 'Use OpenAL if true', False)),
('BF_OPENAL', 'Base path for OpenAL', ''),
diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py
index e1b08d1ff8e..0340c933cdd 100644
--- a/release/scripts/startup/bl_ui/properties_data_modifier.py
+++ b/release/scripts/startup/bl_ui/properties_data_modifier.py
@@ -414,6 +414,74 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
row.operator("object.multires_external_save", text="Save External...")
row.label()
+ def OCEAN(self, layout, ob, md):
+ col = layout.column()
+
+ if not md.build_enabled:
+ col.label("Built without OceanSim modifier")
+ return
+
+ col.prop(md, "geometry_mode")
+
+ if md.geometry_mode == 'GENERATE':
+ row = col.row()
+ row.prop(md, "repeat_x")
+ row.prop(md, "repeat_y")
+
+ col.separator()
+
+ col.prop(md, "time")
+ col.prop(md, "resolution")
+ colflow = col.column_flow()
+ colflow.prop(md, "spatial_size")
+ colflow.prop(md, "depth")
+
+
+ col.label("Waves:")
+ col.prop(md, "choppiness")
+ col.prop(md, "wave_scale", text="Scale")
+
+ col.prop(md, "wave_alignment", text="Alignment")
+ row = col.row()
+ row.active = md.wave_alignment > 0
+ row.prop(md, "wave_direction", text="Direction")
+ row.prop(md, "damp")
+
+ col.prop(md, "smallest_wave")
+ col.prop(md, "wind_velocity")
+
+
+ col = layout.column()
+ col.separator()
+
+ col.prop(md, "generate_normals")
+
+ split = col.split()
+ split.column().prop(md, "generate_foam")
+
+ col = split.column()
+ col.active = md.generate_foam
+ col.prop(md, "foam_coverage", text="Coverage")
+
+
+ col = layout.column()
+ col.separator()
+
+ if md.is_cached:
+ col.operator("object.ocean_bake", text="Free Bake").free=True
+ else:
+ col.operator("object.ocean_bake")
+ row = col.row()
+ row.enabled = not md.is_cached
+ row.prop(md, "bake_start", text="Start")
+ row.prop(md, "bake_end", text="End")
+ col.prop(md, "cachepath")
+
+ #col.prop(md, "bake_foam_fade")
+
+
+
+
def PARTICLE_INSTANCE(self, layout, ob, md):
layout.prop(md, "object")
layout.prop(md, "particle_system_index", text="Particle System")
diff --git a/release/scripts/startup/bl_ui/properties_texture.py b/release/scripts/startup/bl_ui/properties_texture.py
index 9ba0309aacd..70c231b11bf 100644
--- a/release/scripts/startup/bl_ui/properties_texture.py
+++ b/release/scripts/startup/bl_ui/properties_texture.py
@@ -774,6 +774,22 @@ class TEXTURE_PT_pointdensity_turbulence(TextureButtonsPanel, Panel):
col.prop(pd, "turbulence_strength")
+class TEXTURE_PT_ocean(TextureTypePanel, Panel):
+ bl_label = "Ocean"
+ tex_type = 'OCEAN'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ tex = context.texture
+ ot = tex.ocean
+
+ col = layout.column()
+ col.prop(ot, "ocean_object")
+ col.prop(ot, "output")
+
+
class TEXTURE_PT_mapping(TextureSlotPanel, Panel):
bl_label = "Mapping"
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
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 <math.h>
+#include <stdlib.h>
+
+#include <string.h>
+
+#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; v<totvert; v++, mvert++) {
+ min[0]=MIN2(min[0],mvert->co[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 <stddef.h>
+
+#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;
+}
+