Ocean Sim modifier patch
authorLukas Toenne <lukas.toenne@googlemail.com>
Sun, 13 Nov 2011 12:17:27 +0000 (12:17 +0000)
committerLukas Toenne <lukas.toenne@googlemail.com>
Sun, 13 Nov 2011 12:17:27 +0000 (12:17 +0000)
by Matt Ebb, Hamed Zaghaghi

This adds a new Modifier "Ocean" to simulate large-scale wave motion.
Details can be found in the wiki documentation [1], the project homepage [2] and the patch tracker [3]

The modifier is disabled by default for now. To enable it, the WITH_OCEANSIM (cmake) / WITH_BF_OCEANSIM (scons) flags have to be set. The code depends on fftw3, so this also has to be enabled.

[1]
http://wiki.blender.org/index.php/Doc:2.6/Manual/Modifiers/Simulation/Ocean

[2]
http://www.savetheoceansim.com

[3]
http://projects.blender.org/tracker/?group_id=9&atid=127&func=detail&aid=28338

32 files changed:
CMakeLists.txt
SConstruct
build_files/scons/tools/btools.py
release/scripts/startup/bl_ui/properties_data_modifier.py
release/scripts/startup/bl_ui/properties_texture.py
source/blender/blenkernel/BKE_ocean.h [new file with mode: 0644]
source/blender/blenkernel/BKE_texture.h
source/blender/blenkernel/CMakeLists.txt
source/blender/blenkernel/SConscript
source/blender/blenkernel/intern/ocean.c [new file with mode: 0644]
source/blender/blenkernel/intern/texture.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/object/object_intern.h
source/blender/editors/object/object_modifier.c
source/blender/editors/object/object_ops.c
source/blender/makesdna/DNA_modifier_types.h
source/blender/makesdna/DNA_texture_types.h
source/blender/makesrna/RNA_access.h
source/blender/makesrna/SConscript
source/blender/makesrna/intern/CMakeLists.txt
source/blender/makesrna/intern/rna_modifier.c
source/blender/makesrna/intern/rna_texture.c
source/blender/modifiers/CMakeLists.txt
source/blender/modifiers/MOD_modifiertypes.h
source/blender/modifiers/SConscript
source/blender/modifiers/intern/MOD_ocean.c [new file with mode: 0644]
source/blender/modifiers/intern/MOD_util.c
source/blender/render/CMakeLists.txt
source/blender/render/intern/include/texture_ocean.h [new file with mode: 0644]
source/blender/render/intern/source/render_texture.c
source/blender/render/intern/source/texture_ocean.c [new file with mode: 0644]

index 36ef022f3c10291f19fe091d00563cd0ae744a45..40239a16f02b95e694cf12facb8cc2405321baf3 100644 (file)
@@ -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("")
 
index 161bbbc03785efa94c849a0d9372f321ef8cdabf..57da56872aa5137b0154ededa8e4b87f28040c63 100644 (file)
@@ -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__')
index 417bbcc48bad136952cc4c87cc71cc0852daecf0..856231e3c84936aa56595f1b98d02850c56b8105 100644 (file)
@@ -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', ''),
index e1b08d1ff8e86f9d0c10126dff6c0d5b9783b62a..0340c933cdd35f2b384e54e572d0fc071ee186c1 100644 (file)
@@ -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")
index 9ba0309aacd42a1a88e70bd13f7c6fa0bdb9b5c5..70c231b11bf6b679b5bb3a1c5231d4d955958edf 100644 (file)
@@ -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 (file)
index 0000000..c1f228f
--- /dev/null
@@ -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
index 508fef8d9a42b4b7f82f2a1417bfd70c1740d9a4..52fa52a589999f13637e9a3c2ea37efcd1f4f0d1 100644 (file)
@@ -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
index 1fc851bfa72a5f88343b345a46036d70162256c8..4e7561a1bc88bf20e8c85c8f8181c6f8db23e72d 100644 (file)
@@ -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")
index 48a68c433a6c5b2626e394b949fda57a6cc584bc..62a8aa8362f1cf95456425705baa58c6863f754d 100644 (file)
@@ -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 (file)
index 0000000..455acd2
--- /dev/null
@@ -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
index c80b2880d12a9672db07b49a44cf5ce6b2739e6d..fcaeacd2eb4c0bcc66d6ee096fc7d17286f17dcc 100644 (file)
@@ -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)
index 3fd661a52dae058c639f7c8e6a42defa81b2e8a7..9e3feedc5d9f4fb966d15f501028ea5f40a593ec 100644 (file)
 #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;
index 11a80d0d41a6b4763ae8c80899e4c72368a30546..2bb70ce20b517e8cccaaa7fd0a74f4f117beb2fd 100644 (file)
@@ -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) {
index a6e8d4a0a3a87453fa79d8dbbff3117e3246b2fb..185d8d43765259c2312a107aa7f3e82eaa0e844b 100644 (file)
@@ -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);
index ad2280baba2578db107fa5bb320121767ff8dfe1..af9e6592eb562d6991ed1bee2de91ab12ad64cc9 100644 (file)
@@ -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");
+}
+
index 2df49570ee4db73c30c63a01e7421513eed6c89a..56c75331d4894eb80a06890f0741a355f0fd54da 100644 (file)
@@ -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);
index 20001ea6cb67c22c6556391d5a981c510669f7dc..aec984cda3441802e816042cacc91daba785d6f0 100644 (file)
@@ -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;
 
index 1ecca5a0b2a48a9d0a7c1bce559e3b88755c9e13..ece99c8fc862aa7bd9d781ba3bbb0d4f1353116c 100644 (file)
@@ -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
index c9dadce0a5edec0151637ea6ef5cf40ac92d5c06..08e3d1a72a2c7bd427ecc9b33170d841baba4d23 100644 (file)
@@ -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;
index 769ec880a65178a97c5ebe8c3cc03abc7d1b2e0c..9eea6d83cb97975247a7cfa00ada4397bdff861e 100644 (file)
@@ -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'
index 9bc532afa11c76ee8ae5f73affc769dfbae0e2d3..e50617f220c1bedf9c030c9402768e4a6d651b7e 100644 (file)
@@ -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()
index 32665bef065e0394b6446307b672364b12464fcb..aed5ba8840bcbf208f3d565635537c46c42e79d5 100644 (file)
@@ -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
index aac4da9e6f6dd9419511431d86aa29863166f2cd..249bdb4a366e4bb29d2eb8aca3df1f4b87247396 100644 (file)
@@ -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);
index e8ecc75ca60d14856df080920fa6a066d3033607..4aedb4ae7a86626782809697144458871ebd0299 100644 (file)
@@ -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}")
index 8ffb7803bb13e59235e6e15259eab0b993f8d244..cc077694384c308dd8623947059215c9234ea62e 100644 (file)
@@ -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;
index 277ed2c3fb3e754e043f9b17554622fd9cc46f3d..8273ab0d1fe9de05f2cdd82b1c99eb77e9050c2e 100644 (file)
@@ -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 (file)
index 0000000..f36d367
--- /dev/null
@@ -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,
+};
index 38abb96aa7c3ce128dc43ed2c9852efee66545d4..01c7f31b67af1ad7179d3ecac7ba6aeb96f9274c 100644 (file)
@@ -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);
index 763cd3780fbdf6c953bd751a03df12e9512f92c9..c7b27c3cd7ea6694dc36224076a260160553de66 100644 (file)
@@ -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 (file)
index 0000000..b0a0647
--- /dev/null
@@ -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);
index afc52f7c92a9a60f54c6d010e3252f89d5b7dcb9..bd323a5b2d301c422b1e5de0b45f68c8455ece8a 100644 (file)
@@ -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 (file)
index 0000000..c9d84b2
--- /dev/null
@@ -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;
+}
+