* Added a new surface type "Waves" that simulates simple 2D wave motion.
authorMiika Hamalainen <blender@miikah.org>
Sat, 2 Jul 2011 18:06:39 +0000 (18:06 +0000)
committerMiika Hamalainen <blender@miikah.org>
Sat, 2 Jul 2011 18:06:39 +0000 (18:06 +0000)
* Optimized adjacency point searching for vertex surfaces.
* Separated adjacency code from effect system.
* Overall code cleaning and tweaking.

release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py
source/blender/blenkernel/BKE_dynamicpaint.h
source/blender/blenkernel/intern/dynamicpaint.c
source/blender/blenkernel/intern/pointcache.c
source/blender/makesdna/DNA_dynamicpaint_types.h
source/blender/makesrna/intern/rna_dynamicpaint.c

index 52945ab7e11b5c3a103d8067ac8993f5199928d3..806256dd502ff50f4244d8255161e17886241bfd 100644 (file)
@@ -104,7 +104,12 @@ class PHYSICS_PT_dynamic_paint(PhysicButtonsPanel, bpy.types.Panel):
                         col.prop(brush, "paint_color", text="")
                         col.prop(brush, "paint_alpha", text="Alpha")
                 
-                if (brush.brush_settings_context != "GENERAL"):
+                elif (brush.brush_settings_context == "WAVE"):
+                    layout.prop(brush, "wave_type")
+                    if (brush.wave_type != "REFLECT"):
+                        split = layout.split(percentage=0.6)
+                        split.prop(brush, "wave_factor")
+                else:
                     layout.label(text="-WIP-")
 
 
@@ -131,7 +136,7 @@ class PHYSICS_PT_dp_advanced_canvas(PhysicButtonsPanel, bpy.types.Panel):
             split.prop(surface, "dry_speed", text="Dry Time")
             split.prop(surface, "use_dry_log", text="Slow")
             
-        if (surface.surface_type != "IWAVE"):
+        if (surface.surface_type != "WAVE"):
             if (surface.surface_type == "DISPLACE"):
                 layout.prop(surface, "use_dissolve", text="Dissolve:")
             elif (surface.surface_type == "WEIGHT"):
@@ -144,6 +149,19 @@ class PHYSICS_PT_dp_advanced_canvas(PhysicButtonsPanel, bpy.types.Panel):
             split.prop(surface, "dissolve_speed", text="Time")
             split.prop(surface, "use_dissolve_log", text="Slow")
             
+        if (surface.surface_type == "WAVE"):
+            layout.prop(surface, "wave_open_borders")
+            
+            split = layout.split()
+            
+            col = split.column(align=True)
+            col.prop(surface, "wave_timescale")
+            col.prop(surface, "wave_speed")
+            
+            col = split.column(align=True)
+            col.prop(surface, "wave_damping")
+            col.prop(surface, "wave_spring")
+            
         layout.label(text="Brush Group:")
         layout.prop(surface, "brush_group", text="")
 
@@ -158,7 +176,7 @@ class PHYSICS_PT_dp_canvas_output(PhysicButtonsPanel, bpy.types.Panel):
         if ((not md) or (md.dynamicpaint_type != 'CANVAS')):
             return 0
         surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active
-        return (surface and (not (surface.surface_format=="VERTEX" and surface.surface_type=="DISPLACE") ))
+        return (surface and not (surface.surface_format=="VERTEX" and (surface.surface_type=="DISPLACE" or surface.surface_type=="WAVE")))
 
     def draw(self, context):
         layout = self.layout
@@ -202,9 +220,10 @@ class PHYSICS_PT_dp_canvas_output(PhysicButtonsPanel, bpy.types.Panel):
                 sub = col.column()
                 sub.active = surface.do_output2
                 sub.prop(surface, "output_name2", text="Filename: ")
-            if (surface.surface_type == "DISPLACE"):
+            else:
                 col.prop(surface, "output_name", text="Filename: ")
-                col.prop(surface, "disp_type", text="Displace Type")
+                if (surface.surface_type == "DISPLACE"):
+                    col.prop(surface, "disp_type", text="Displace Type")
             
             layout.separator()
             layout.operator("dpaint.bake", text="Bake Image Sequence", icon='MOD_DYNAMICPAINT')
index 03b64163ce4ea99cb22ae819a8a12d7f3bd2ab70..f9b16336de8b2d80351f8faca245d41304a95a5f 100644 (file)
@@ -24,8 +24,8 @@ typedef struct PaintSurfaceData {
        void *format_data;
        /* surface type data */
        void *type_data;
-       /* paint effects data */
-       struct PaintEffectData *eff_data;
+       /* point neighbor data */
+       struct PaintAdjData *adj_data;
 
        unsigned int total_points;
        short samples;
@@ -49,27 +49,28 @@ typedef struct PaintPoint {
        float alpha;
 } PaintPoint;
 
-/* iWave type surface point    */
-typedef struct PaintIWavePoint {               
-
-       float source;
-       float obstruction;
-       float height, previousHeight;
+/* heigh field waves   */
+typedef struct PaintWavePoint {                
 
+       float height;
+       float velocity;
+       short state; /* 0 = neutral
+                                *  1 = obstacle
+                                *  2 = reflect only */
        float foam;
 
-       float verticalDerivative;
-
-} PaintIWavePoint;
+} PaintWavePoint;
 
 struct DerivedMesh *dynamicPaint_Modifier_do(struct DynamicPaintModifierData *pmd, struct Scene *scene, struct Object *ob, struct DerivedMesh *dm);
-void dynamicPaint_cacheUpdateFrames(struct DynamicPaintSurface *surface);
-int dynamicPaint_resetSurface(struct DynamicPaintSurface *surface);
-int dynamicPaint_surfaceHasPreview(DynamicPaintSurface *surface);
-void dynamicPaintSurface_updateType(struct DynamicPaintSurface *surface);
-void dynamicPaintSurface_setUniqueName(DynamicPaintSurface *surface, char *basename);
 void dynamicPaint_Modifier_free (struct DynamicPaintModifierData *pmd);
 void dynamicPaint_Modifier_createType(struct DynamicPaintModifierData *pmd);
 void dynamicPaint_Modifier_copy(struct DynamicPaintModifierData *pmd, struct DynamicPaintModifierData *tsmd);
 
+void dynamicPaint_cacheUpdateFrames(struct DynamicPaintSurface *surface);
+void dynamicPaint_clearSurface(DynamicPaintSurface *surface);
+int  dynamicPaint_resetSurface(struct DynamicPaintSurface *surface);
+int  dynamicPaint_surfaceHasPreview(DynamicPaintSurface *surface);
+void dynamicPaintSurface_updateType(struct DynamicPaintSurface *surface);
+void dynamicPaintSurface_setUniqueName(DynamicPaintSurface *surface, char *basename);
+
 #endif /* BKE_DYNAMIC_PAINT_H_ */
index dbf95135888a1e0f975b2bb71f478dab9403a249..f0785d1f0fe81e5714a04bad29060f3f1d989bc9 100644 (file)
@@ -166,20 +166,23 @@ typedef struct EffVelPoint {
        float previous_vel[3];
 } EffVelPoint;
 
-typedef struct EffBakeNPoint {
+typedef struct BakeNeighPoint {
        float dir[3];   /* vector pointing towards this neighbour */
        float dist;             /* distance to */
-} EffBakeNPoint;
+} BakeNeighPoint;
 
-typedef struct PaintEffectData {
+
+/* adjacency data flags */
+#define ADJ_ON_MESH_EDGE (1<<0)
+
+typedef struct PaintAdjData {
        unsigned int *n_index;          /* total_points sized index array */
        unsigned int *numOf_n;          /* num of neighs for each point */
        unsigned int *n_target;         /* array of neighbouring point indexes
                                                           for single sample use n_index+neigh_num */
+       unsigned int *flags;            /* for each point */
        unsigned int total_targets; /* size of n_target */
-       unsigned int most_neighs;
-       //EffVelPoint *v_point;
-} PaintEffectData;
+} PaintAdjData;
 
 /***************************** General Utils ******************************/
 
@@ -286,8 +289,8 @@ void dynamicPaintSurface_updateType(struct DynamicPaintSurface *surface) {
        else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
                strcat(surface->output_name,"weight");
        }
-       else if (surface->type == MOD_DPAINT_SURFACE_T_IWAVE) {
-               strcat(surface->output_name,"iwave");
+       else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
+               strcat(surface->output_name,"wave");
                strcat(surface->output_name2,"foam");
        }
 
@@ -354,11 +357,12 @@ static void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd)
 
 static void dynamicPaint_freeEffectData(PaintSurfaceData *data)
 {
-       if (data->eff_data) {
-               if (data->eff_data->n_index) MEM_freeN(data->eff_data->n_index);
-               if (data->eff_data->numOf_n) MEM_freeN(data->eff_data->numOf_n);
-               if (data->eff_data->n_target) MEM_freeN(data->eff_data->n_target);
-               MEM_freeN(data->eff_data);
+       if (data->adj_data) {
+               if (data->adj_data->n_index) MEM_freeN(data->adj_data->n_index);
+               if (data->adj_data->numOf_n) MEM_freeN(data->adj_data->numOf_n);
+               if (data->adj_data->n_target) MEM_freeN(data->adj_data->n_target);
+               if (data->adj_data->flags) MEM_freeN(data->adj_data->flags);
+               MEM_freeN(data->adj_data);
        }
 }
 
@@ -474,6 +478,11 @@ static DynamicPaintSurface *dynamicPaint_createNewSurface(DynamicPaintCanvasSett
        surface->spread_speed = 1.0f;
        surface->shrink_speed = 1.0f;
 
+       surface->wave_damping = 0.05f;
+       surface->wave_speed = 0.8f;
+       surface->wave_timescale = 1.0f;
+       surface->wave_spring = 0.20;
+
        sprintf(surface->image_output_path, "%sdynamicpaint/", "/tmp/");
        dynamicPaintSurface_setUniqueName(surface, "Surface");
 
@@ -534,8 +543,10 @@ void dynamicPaint_Modifier_createType(struct DynamicPaintModifierData *pmd)
                        pmd->brush->displace_distance = 0.5f;
                        pmd->brush->prox_displace_strength = 0.5f;
 
-                       pmd->brush->particle_radius = 0.2;
-                       pmd->brush->particle_smooth = 0.05;
+                       pmd->brush->particle_radius = 0.2f;
+                       pmd->brush->particle_smooth = 0.05f;
+
+                       pmd->brush->wave_factor = 1.0f;
 
                        pmd->brush->dm = NULL;
 
@@ -636,22 +647,27 @@ static void dynamicPaint_allocateSurfaceType(DynamicPaintSurface *surface)
        else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
                sData->type_data = MEM_callocN(sizeof(float)*sData->total_points, "DynamicPaintSurface WeightData");
        }
-       else if (surface->type == MOD_DPAINT_SURFACE_T_IWAVE) {
-               sData->type_data = MEM_callocN(sizeof(PaintIWavePoint)*sData->total_points, "DynamicPaintSurface iWaveData");
+       else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
+               sData->type_data = MEM_callocN(sizeof(PaintWavePoint)*sData->total_points, "DynamicPaintSurface WaveData");
        }
        else return;
 
        if (sData->type_data == NULL) printError(surface->canvas, "Not enough free memory!");
 }
 
+static int surface_usesNeighData(DynamicPaintSurface *surface) {
+       return (surface->type == MOD_DPAINT_SURFACE_T_PAINT ||
+                   surface->type == MOD_DPAINT_SURFACE_T_WAVE);
+}
 
-/* initialize "paint effect" data */
-static void dynamicPaint_initEffectData(DynamicPaintSurface *surface) {
+/* initialize surface adjacency data */
+static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface) {
        PaintSurfaceData *sData = surface->data;
-       PaintEffectData *ed;
+       PaintAdjData *ed;
+       int *temp_data;
        int neigh_points = 0;
 
-       if (!surface->effect) return;
+       if (!surface->effect && !surface_usesNeighData(surface)) return;
 
        if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
                /* For vertex format, neighbours are connected by edges */
@@ -663,58 +679,110 @@ static void dynamicPaint_initEffectData(DynamicPaintSurface *surface) {
        if (!neigh_points) return;
 
        /* allocate memory */
-       ed = sData->eff_data = MEM_callocN(sizeof(PaintEffectData), "Surface Effect Data");
+       ed = sData->adj_data = MEM_callocN(sizeof(PaintAdjData), "Surface Adj Data");
        if (!ed) return;
-       ed->n_index = MEM_callocN(sizeof(int)*sData->total_points, "Surface Effect Index");
-       ed->numOf_n = MEM_callocN(sizeof(int)*sData->total_points, "Surface Effect Counts");
-       ed->n_target = MEM_callocN(sizeof(int)*neigh_points, "Surface Effect Neighs");
+       ed->n_index = MEM_callocN(sizeof(int)*sData->total_points, "Surface Adj Index");
+       ed->numOf_n = MEM_callocN(sizeof(int)*sData->total_points, "Surface Adj Counts");
+       temp_data = MEM_callocN(sizeof(int)*sData->total_points, "Temp Adj Data");
+       ed->n_target = MEM_callocN(sizeof(int)*neigh_points, "Surface Adj Targets");
+       ed->flags = MEM_callocN(sizeof(int)*sData->total_points, "Surface Adj Flags");
        ed->total_targets = neigh_points;
-       ed->most_neighs = 0;
 
        /* in case of error, free allocated memory */
-       if (!ed->n_index || !ed->numOf_n || !ed->n_target) {
+       if (!ed->n_index || !ed->numOf_n || !ed->n_target || !temp_data) {
                dynamicPaint_freeEffectData(sData);
+               MEM_freeN(temp_data);
                printError(surface->canvas, "Not enough free memory.");
                return;
        }
 
        if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
-               int i,j;
+               int i;
                int n_pos;
 
                /* For vertex format, count every vertex that is connected by an edge */
                int numOfEdges = surface->canvas->dm->getNumEdges(surface->canvas->dm);
+               int numOfFaces = surface->canvas->dm->getNumFaces(surface->canvas->dm);
                struct MEdge *edge =  surface->canvas->dm->getEdgeArray(surface->canvas->dm);
+               struct MFace *face =  surface->canvas->dm->getFaceArray(surface->canvas->dm);
 
-               /* add neighbour data */
+               /* count number of edges per vertex */
+               for (i=0; i<numOfEdges; i++) {
+                       ed->numOf_n[edge[i].v1]++;
+                       ed->numOf_n[edge[i].v2]++;
+
+                       temp_data[edge[i].v1]++;
+                       temp_data[edge[i].v2]++;
+               }
+
+               /* to locate points on "mesh edge" */
+               for (i=0; i<numOfFaces; i++) {
+                       temp_data[face[i].v1]++;
+                       temp_data[face[i].v2]++;
+                       temp_data[face[i].v3]++;
+                       if (face[i].v4)
+                               temp_data[face[i].v4]++;
+               }
+
+               /* now check if total number of edges+faces for
+               *  each vertex is even, if not -> vertex is on mesh edge */
+               for (i=0; i<sData->total_points; i++) {
+                       if ((temp_data[i]%2) ||
+                               temp_data[i] < 4)
+                               ed->flags[i] |= ADJ_ON_MESH_EDGE;
+                               
+                       /* reset temp data */ 
+                       temp_data[i] = 0;
+               }
+
+               /* order n_index array */
                n_pos = 0;
                for (i=0; i<sData->total_points; i++) {
                        ed->n_index[i] = n_pos;
-                       ed->numOf_n[i] = 0;
+                       n_pos += ed->numOf_n[i];
+               }
 
-                       for (j=0; j<numOfEdges; j++) {
-                               if (edge[j].v1 == i) {
-                                       ed->n_target[n_pos] = edge[j].v2;
-                                       ed->numOf_n[i]++;
-                                       n_pos++;
-                               }
-                               else if (edge[j].v2 == i) {
-                                       ed->n_target[n_pos] = edge[j].v1;
-                                       ed->numOf_n[i]++;
-                                       n_pos++;
-                               }
-                       }
-                       if (ed->numOf_n[i] > ed->most_neighs)
-                               ed->most_neighs = ed->numOf_n[i];
+               /* and now add neighbour data using that info */
+               for (i=0; i<numOfEdges; i++) {
+                       /* first vertex */
+                       int index = edge[i].v1;
+                       n_pos = ed->n_index[index]+temp_data[index];
+                       ed->n_target[n_pos] = edge[i].v2;
+                       temp_data[index]++;
+
+                       /* second vertex */
+                       index = edge[i].v2;
+                       n_pos = ed->n_index[index]+temp_data[index];
+                       ed->n_target[n_pos] = edge[i].v1;
+                       temp_data[index]++;
                }
        }
        else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
                /* for image sequences, only allocate memory.
                *  bake initialization takes care of rest */
        }
+
+       MEM_freeN(temp_data);
 }
 
-/* (re)initialize surface data (only for point cache types)*/
+/* clears surface data back to zero */
+void dynamicPaint_clearSurface(DynamicPaintSurface *surface) {
+       PaintSurfaceData *sData = surface->data;
+       if (sData && sData->type_data) {
+               unsigned int data_size;
+
+               if (surface->type == MOD_DPAINT_SURFACE_T_PAINT)
+                       data_size = sizeof(PaintPoint);
+               else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE)
+                       data_size = sizeof(PaintWavePoint);
+               else
+                       data_size = sizeof(float);
+
+               memset(sData->type_data, 0, data_size * sData->total_points);
+       }
+}
+
+/* completely (re)initializes surface (only for point cache types)*/
 int dynamicPaint_resetSurface(DynamicPaintSurface *surface)
 {
        int numOfPoints = dynamicPaint_surfaceNumOfPoints(surface);
@@ -732,7 +800,7 @@ int dynamicPaint_resetSurface(DynamicPaintSurface *surface)
        surface->data->total_points = numOfPoints;
        surface->data->samples = 1;
        dynamicPaint_allocateSurfaceType(surface);
-       dynamicPaint_initEffectData(surface);
+       dynamicPaint_initAdjacencyData(surface);
 
        return 1;
 }
@@ -988,7 +1056,7 @@ struct DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, S
                                                        *   able to share same drawing methods */
                                                        MFace *mface = result->getFaceArray(result);
                                                        int numOfFaces = result->getNumFaces(result);
-                                                       int i,j;
+                                                       int i;
                                                        MCol *col = result->getFaceDataArray(result, CD_WEIGHT_MCOL);
                                                        if (!col) col = CustomData_add_layer(&result->faceData, CD_WEIGHT_MCOL, CD_CALLOC, NULL, numOfFaces);
 
@@ -1050,6 +1118,24 @@ struct DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, S
                                                        }
                                                }
                                        }
+                                       /* wave simulation */
+                                       else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
+                                               MVert *mvert = result->getVertArray(result);
+                                               int i;
+                                               float normal[3];
+                                               PaintWavePoint* wPoint = (PaintWavePoint*)surface->data->type_data;
+
+                                               for (i=0; i<surface->data->total_points; i++) {
+                                                       normal_short_to_float_v3(normal, mvert[i].no);
+                                                       normalize_v3(normal);
+
+                                                       mvert[i].co[0] += normal[0]*wPoint[i].height;
+                                                       mvert[i].co[1] += normal[1]*wPoint[i].height;
+                                                       mvert[i].co[2] += normal[2]*wPoint[i].height;
+                                               }
+
+                                               CDDM_calc_normals(result);
+                                       }
                                }
                        }
                }
@@ -1133,7 +1219,6 @@ static int dynamicPaint_findNeighbourPixel(PaintUVPoint *tempPoints, DerivedMesh
        */
        {
                int numOfFaces = dm->getNumFaces(dm);
-               MVert *mvert = dm->getVertArray(dm);
                MFace *mface = dm->getFaceArray(dm);
                MTFace *tface =  CustomData_get_layer_named(&dm->faceData, CD_MTFACE, uvname);
 
@@ -1607,7 +1692,7 @@ static int dynamicPaint_createUVSurface(DynamicPaintSurface *surface)
 
                /*      If any effect enabled, create surface effect / wet layer
                *       neighbour lists. Processes possibly moving data. */
-               if (surface->effect) {
+               if (surface_usesNeighData(surface)) {
 
                        int i, cursor=0;
 
@@ -1622,10 +1707,10 @@ static int dynamicPaint_createUVSurface(DynamicPaintSurface *surface)
 
                        /* allocate memory */
                        sData->total_points = w*h;
-                       dynamicPaint_initEffectData(surface);
+                       dynamicPaint_initAdjacencyData(surface);
 
-                       if (sData->eff_data) {
-                               PaintEffectData *ed = sData->eff_data;
+                       if (sData->adj_data) {
+                               PaintAdjData *ed = sData->adj_data;
                                unsigned int n_pos = 0;
                                //#pragma omp parallel for schedule(static)
                                for (yy = 0; yy < h; yy++)
@@ -1634,7 +1719,6 @@ static int dynamicPaint_createUVSurface(DynamicPaintSurface *surface)
                                        for (xx = 0; xx < w; xx++)
                                        {
                                                int i, index = xx+w*yy;
-                                               PaintUVPoint *tPoint = (&tempPoints[index]);
 
                                                if (tempPoints[index].face_index != -1) {
                                                        ed->n_index[final_index[index]] = n_pos;
@@ -1652,10 +1736,6 @@ static int dynamicPaint_createUVSurface(DynamicPaintSurface *surface)
                                                                        n_pos++;
                                                                }
                                                        }
-
-                                                       if (ed->numOf_n[final_index[index]] > ed->most_neighs)
-                                                               ed->most_neighs = ed->numOf_n[final_index[index]];
-
                                                }
                                        }
                                }
@@ -1707,7 +1787,6 @@ static int dynamicPaint_createUVSurface(DynamicPaintSurface *surface)
 
        /* Init surface type data */
        if (!error) {
-               int index;
                dynamicPaint_allocateSurfaceType(surface);
 
 #if 0
@@ -1739,7 +1818,7 @@ static int dynamicPaint_createUVSurface(DynamicPaintSurface *surface)
 #define DPOUTPUT_PAINT 0
 #define DPOUTPUT_WET 1
 #define DPOUTPUT_DISPLACE 2
-#define DPOUTPUT_IWAVE 3
+#define DPOUTPUT_WAVES 3
 
 /*
 *      Outputs an image file from uv surface data.
@@ -1810,6 +1889,15 @@ void dynamicPaint_outputImage(DynamicPaintSurface *surface, char* filename, shor
                                if (depth > 1.0f) depth = 1.0f;
                        }
 
+                       mhImgB->rect_float[pos]=depth;
+                       mhImgB->rect_float[pos+1]=depth;
+                       mhImgB->rect_float[pos+2]=depth;
+                       mhImgB->rect_float[pos+3]=1.0f;
+               }
+               else if (type == DPOUTPUT_WAVES) {
+                       PaintWavePoint *wPoint = &((PaintWavePoint*)sData->type_data)[index];
+                       float depth = wPoint->height/2.0f+0.5f;
+
                        mhImgB->rect_float[pos]=depth;
                        mhImgB->rect_float[pos+1]=depth;
                        mhImgB->rect_float[pos+2]=depth;
@@ -2435,7 +2523,7 @@ static void mesh_faces_nearest_point_dp(void *userdata, int index, const float *
 *      timescale : value used to adjust time dependand
 *                          operations when using substeps
 */
-void dynamicPaint_mixPaintColors(DynamicPaintSurface *surface, int index, int paintFlags, float *paintColor, float *paintAlpha, float *paintWetness, float *timescale)
+static void dynamicPaint_mixPaintColors(DynamicPaintSurface *surface, int index, int paintFlags, float *paintColor, float *paintAlpha, float *paintWetness, float *timescale)
 {
        PaintPoint *pPoint = &((PaintPoint*)surface->data->type_data)[index];
 
@@ -2491,6 +2579,30 @@ void dynamicPaint_mixPaintColors(DynamicPaintSurface *surface, int index, int pa
        }
 }
 
+static void dynamicPaint_mixWaveHeight(PaintWavePoint *wPoint, DynamicPaintBrushSettings *brush, float isect_height)
+{
+       int hit = 0;
+       isect_height *= brush->wave_factor;
+
+       /* determine hit depending on wave_factor */
+       if (brush->wave_factor > 0.0f && wPoint->height > isect_height)
+               hit = 1;
+       else if (brush->wave_factor < 0.0f && wPoint->height < isect_height)
+               hit = 1;
+
+       if (hit) {
+               if (brush->wave_type == MOD_DPAINT_WAVEB_DEPTH) {
+                       wPoint->height = isect_height;
+                       wPoint->state = 1;
+                       wPoint->velocity = 0.0f;
+               }
+               else if (brush->wave_type == MOD_DPAINT_WAVEB_FORCE)
+                       wPoint->velocity = isect_height;
+               else if (brush->wave_type == MOD_DPAINT_WAVEB_REFLECT)
+                       wPoint->state = 2;
+       }
+}
+
 /*
 *      Paint a brush object mesh to the surface
 */
@@ -2757,6 +2869,7 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface, PaintBakeData *b
                                                        */
                                                        dynamicPaint_mixPaintColors(surface, index, brush->flags, paintColor, &paintAlpha, &paintWetness, &timescale);
                                                }
+                                               /* displace */
                                                else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
                                                        float *value = (float*)sData->type_data;
 
@@ -2770,6 +2883,7 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface, PaintBakeData *b
                                                                if (value[index] < depth) value[index] = depth;
                                                        }
                                                }
+                                               /* vertex weight */
                                                else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
                                                        float *value = (float*)sData->type_data;
 
@@ -2787,6 +2901,13 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface, PaintBakeData *b
                                                                }
                                                        }
                                                }
+                                               /* wave */
+                                               else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
+                                                       depth *= -1.0f/bData->bPoint[index].normal_scale;
+
+                                                       dynamicPaint_mixWaveHeight(&((PaintWavePoint*)surface->data->type_data)[index],
+                                                                       brush, depth);
+                                               }
                                        }
                                }
                        }
@@ -2970,6 +3091,18 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface, PaintBakeDa
                                if (value[index] < strength) value[index] = strength;
                        }
                }
+               /* wave */
+               else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
+                       float sdepth;
+
+                       /* change falloff type to inverse square to match real displace depth   */
+                       disp_intersect = (1.0f - sqrt(disp_intersect / radius)) * radius;
+                       /* get displace depth   */
+                       sdepth = -1.0f * (radius - disp_intersect) / bData->bPoint[index].normal_scale;
+
+                       dynamicPaint_mixWaveHeight(&((PaintWavePoint*)surface->data->type_data)[index],
+                                       brush, sdepth);
+               }
        }
        BLI_kdtree_free(tree);
 
@@ -2979,6 +3112,35 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface, PaintBakeDa
 
 /***************************** Dynamic Paint Step / Baking ******************************/
 
+/*
+*      Calculate current frame neighbouring point distances
+*      and direction vectors
+*/
+static void dynamicPaint_prepareNeighbourData(DynamicPaintSurface *surface, BakeNeighPoint *bNeighs, float *realCoords)
+{
+       PaintSurfaceData *sData = surface->data;
+       int index;
+
+       #pragma omp parallel for schedule(static)
+       for (index = 0; index < sData->total_points; index++)
+       {
+               int i;
+               int numOfNeighs = sData->adj_data->numOf_n[index];
+
+               for (i=0; i<numOfNeighs; i++) {
+                       int n_index = sData->adj_data->n_index[index]+i;
+                       int t_index = sData->adj_data->n_target[n_index];
+
+                       /* dir vec */
+                       sub_v3_v3v3(bNeighs[n_index].dir, &realCoords[t_index*3], &realCoords[index*3]);
+                       /* dist */
+                       bNeighs[n_index].dist = len_v3(bNeighs[n_index].dir);
+                       /* normalize dir */
+                       if (bNeighs[n_index].dist) mul_v3_fl(bNeighs[n_index].dir, 1.0f/bNeighs[n_index].dist);
+               }
+       }
+}
+
 /* paint effect default movement per frame in global units */
 #define EFF_MOVEMENT_PER_FRAME 0.05f
 
@@ -2986,7 +3148,7 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface, PaintBakeDa
 *      Prepare data required by effects for current frame.
 *      Returns number of steps required
 */
-static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *scene, Object *ob, EffBakeNPoint *eNeighs, float **force, float *realCoords, float timescale)
+static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *scene, Object *ob, BakeNeighPoint *bNeighs, float **force, float *realCoords, float timescale)
 {
        double average_dist = 0.0f;
        double average_force = 0.0f;
@@ -2999,7 +3161,6 @@ static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *s
        /* Init force data if required */
        if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
                float vel[3] = {0};
-               float f_t[3];
                ListBase *effectors = pdInitEffectors(scene, ob, NULL, surface->effector_weights);
 
                /* allocate memory for force data (dir vector + strength) */
@@ -3036,44 +3197,21 @@ static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *s
                pdEndEffectors(&effectors);
        }
 
-       /*
-       *       Calculate current frame neighbouring pixel distances
-       *       and average distance between those neighbours
-       */
-       #pragma omp parallel for schedule(static)
+       /* calculate average values (single thread) */
        for (index = 0; index < sData->total_points; index++)
        {
                int i;
-               int numOfNeighs = sData->eff_data->numOf_n[index];
-
-               for (i=0; i<numOfNeighs; i++) {
-                       int n_index = sData->eff_data->n_index[index]+i;
-                       int t_index = sData->eff_data->n_target[n_index];
-
-                       /* dir vec */
-                       sub_v3_v3v3(eNeighs[n_index].dir, &realCoords[t_index*3], &realCoords[index*3]);
-                       /* dist */
-                       eNeighs[n_index].dist = len_v3(eNeighs[n_index].dir);
-                       /* normalize dir */
-                       if (eNeighs[n_index].dist) mul_v3_fl(eNeighs[n_index].dir, 1.0f/eNeighs[n_index].dist);
-               }
-       }
-
-       /* calculate average values single thread */
-       for (index = 0; index < sData->total_points; index++)
-       {
-               int i;
-               int numOfNeighs = sData->eff_data->numOf_n[index];
+               int numOfNeighs = sData->adj_data->numOf_n[index];
 
                if (*force)
                        average_force += (*force)[index*4+3];
 
                for (i=0; i<numOfNeighs; i++) {
-                       average_dist += eNeighs[sData->eff_data->n_index[index]+i].dist;
+                       average_dist += bNeighs[sData->adj_data->n_index[index]+i].dist;
                }
        }
        average_force /= sData->total_points;
-       average_dist  /= sData->eff_data->total_targets;
+       average_dist  /= sData->adj_data->total_targets;
 
        /* Get number of required steps using averate point distance
        *  so that just a few ultra close pixels wont up substeps to max */
@@ -3097,12 +3235,12 @@ static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *s
 /*
 *      Processes active effect step.
 */
-static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, EffBakeNPoint *eNeighs, float *force, PaintPoint *prevPoint, float timescale)
+static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, BakeNeighPoint *bNeighs, float *force, PaintPoint *prevPoint, float timescale)
 {
        PaintSurfaceData *sData = surface->data;
        int index;
 
-       if (!sData->eff_data) return;
+       if (!sData->adj_data) return;
        /*
        *       Spread Effect
        */
@@ -3116,7 +3254,7 @@ static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, EffBakeNPoin
                for (index = 0; index < sData->total_points; index++)
                {
                        int i;
-                       int numOfNeighs = sData->eff_data->numOf_n[index];
+                       int numOfNeighs = sData->adj_data->numOf_n[index];
                        float totalAlpha = 0.0f;
                        PaintPoint *pPoint = &((PaintPoint*)sData->type_data)[index];
 
@@ -3127,10 +3265,10 @@ static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, EffBakeNPoin
 
                        /*      Loop through neighbouring points        */
                        for (i=0; i<numOfNeighs; i++) {
-                               int n_index = sData->eff_data->n_index[index]+i;
+                               int n_index = sData->adj_data->n_index[index]+i;
                                float w_factor, alphaAdd = 0.0f;
-                               PaintPoint *ePoint = &prevPoint[sData->eff_data->n_target[n_index]];
-                               float speed_scale = (eNeighs[n_index].dist<eff_scale) ? 1.0f : eff_scale/eNeighs[n_index].dist;
+                               PaintPoint *ePoint = &prevPoint[sData->adj_data->n_target[n_index]];
+                               float speed_scale = (bNeighs[n_index].dist<eff_scale) ? 1.0f : eff_scale/bNeighs[n_index].dist;
 
                                totalAlpha += ePoint->e_alpha;
 
@@ -3174,14 +3312,14 @@ static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, EffBakeNPoin
                for (index = 0; index < sData->total_points; index++)
                {
                        int i;
-                       int numOfNeighs = sData->eff_data->numOf_n[index];
+                       int numOfNeighs = sData->adj_data->numOf_n[index];
                        float totalAlpha = 0.0f;
                        PaintPoint *pPoint = &((PaintPoint*)sData->type_data)[index];
 
                        for (i=0; i<numOfNeighs; i++) {
-                               int n_index = sData->eff_data->n_index[index]+i;
-                               float speed_scale = (eNeighs[n_index].dist<eff_scale) ? 1.0f : eff_scale/eNeighs[n_index].dist;
-                               PaintPoint *ePoint = &prevPoint[sData->eff_data->n_target[n_index]];
+                               int n_index = sData->adj_data->n_index[index]+i;
+                               float speed_scale = (bNeighs[n_index].dist<eff_scale) ? 1.0f : eff_scale/bNeighs[n_index].dist;
+                               PaintPoint *ePoint = &prevPoint[sData->adj_data->n_target[n_index]];
                                float a_factor, ea_factor, w_factor;
 
                                totalAlpha += ePoint->e_alpha;
@@ -3222,99 +3360,89 @@ static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, EffBakeNPoin
        if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP && force) 
        {
                float eff_scale = EFF_MOVEMENT_PER_FRAME*timescale/10.0f;
-               float *str = MEM_callocN(sData->eff_data->most_neighs*sizeof(float), "PaintEffectForces");
+               for (index = 0; index < sData->total_points; index++) {
+                       int i;
+                       int numOfNeighs = sData->adj_data->numOf_n[index];
+                       PaintPoint *pPoint = &((PaintPoint*)sData->type_data)[index];
 
-               /* Copy current surface to the previous points array to read unmodified values  */
-               memcpy(prevPoint, sData->type_data, sData->total_points*sizeof(struct PaintPoint));
+                       /* to make dripping happen with as little spread as possible,
+                       *  only use two closest point dirs "around" the force dir */
+                       int closest_id[2] = {-1, -1};
+                       float closest_d[2] = {-1.0f, -1.0f};
 
-               if (str)
-               {
-                       for (index = 0; index < sData->total_points; index++) {
-                               int i;
-                               int numOfNeighs = sData->eff_data->numOf_n[index];
-                               float totalStr = 0.0f, str_factor;
-                               PaintPoint *pPoint = &((PaintPoint*)sData->type_data)[index];
-
-                               /* to make dripping happen with as little spread as possible,
-                               *  find two closest point dirs around the force dir */
-                               int closest_id[2] = {-1, -1};
-                               float closest_d[2] = {-1.0f, -1.0f};
-
-                               /* find closest neigh dir */
-                               for (i=0; i<numOfNeighs; i++) {
-                                       int n_index = sData->eff_data->n_index[index]+i;
-                                       float dir_dot = dot_v3v3(eNeighs[n_index].dir, &force[index*4]);
-
-                                       if (dir_dot>closest_d[0] && dir_dot>0.0f) {closest_d[0]=dir_dot; closest_id[0]=n_index;}
-                               }
+                       /* adjust drip speed depending on wetness */
+                       float w_factor = pPoint->wetness*0.4 - 0.05f;
+                       if (w_factor <= 0) continue;
+                       w_factor *= w_factor;
 
-                               /* find other neigh */
-                               for (i=0; i<numOfNeighs; i++) {
-                                       int n_index = sData->eff_data->n_index[index]+i;
-                                       float dir_dot = dot_v3v3(eNeighs[n_index].dir, &force[index*4]);
-                                       float closest_dot = dot_v3v3(eNeighs[n_index].dir, eNeighs[closest_id[0]].dir);
+                       /* find closest neigh dir */
+                       for (i=0; i<numOfNeighs; i++) {
+                               int n_index = sData->adj_data->n_index[index]+i;
+                               float dir_dot = dot_v3v3(bNeighs[n_index].dir, &force[index*4]);
 
-                                       if (n_index == closest_id[0]) continue;
+                               if (dir_dot>closest_d[0] && dir_dot>0.0f) {closest_d[0]=dir_dot; closest_id[0]=n_index;}
+                       }
 
-                                       /* only accept neighbour at "other side" of the first one in relation to force dir
-                                       *  so make sure angle between this and closest neigh is greater than first angle */
-                                       if (dir_dot>closest_d[1] && closest_dot<closest_d[0] && dir_dot>0.0f) {closest_d[1]=dir_dot; closest_id[1]=n_index;}
-                               }
+                       /* find other neigh */
+                       for (i=0; i<numOfNeighs; i++) {
+                               int n_index = sData->adj_data->n_index[index]+i;
+                               float dir_dot = dot_v3v3(bNeighs[n_index].dir, &force[index*4]);
+                               float closest_dot = dot_v3v3(bNeighs[n_index].dir, bNeighs[closest_id[0]].dir);
 
-                               /* if two valid neighs found, change closest_d
-                               *  values to match final paint factors */
-                               if (closest_id[1] != -1) {
-                                       float neigh_diff = dot_v3v3(eNeighs[closest_id[0]].dir, eNeighs[closest_id[1]].dir);
-                                       /* linearize both values */
-                                       neigh_diff *= neigh_diff;
-                                       closest_d[0] *= closest_d[0];
-
-                                       /* get relation to angle between neighs */
-                                       closest_d[0] -= neigh_diff;
-                                       /* and normalize as relative angle within neigh range */
-                                       closest_d[0] /= 1.0f - neigh_diff;
-
-                                       /* simply set other neigh to cover missing half of this factor */
-                                       closest_d[1] = 1.0f - closest_d[0];
-                               }
-                               else if (closest_id[0] != -1) {
-                                       /* if only one neigh, still linearize to minimize spread */
-                                       closest_d[0] *= closest_d[0];
-                               }
+                               if (n_index == closest_id[0]) continue;
 
+                               /* only accept neighbour at "other side" of the first one in relation to force dir
+                               *  so make sure angle between this and closest neigh is greater than first angle */
+                               if (dir_dot>closest_d[1] && closest_dot<closest_d[0] && dir_dot>0.0f) {closest_d[1]=dir_dot; closest_id[1]=n_index;}
+                       }
 
-                               /* Apply movement towards those two points */
-                               for (i=0; i<2; i++) {
-                                       int n_index = closest_id[i];
-                                       if (n_index != -1 && closest_d[i]>0.0f) {
-                                               float dir_dot = closest_d[i], dir_factor, w_factor;
-                                               float speed_scale = eff_scale*force[index*4+3]/eNeighs[n_index].dist;
-                                               PaintPoint *ePoint = &((PaintPoint*)sData->type_data)[sData->eff_data->n_target[n_index]];
+                       /* if two valid neighs found, change closest_d
+                       *  values to match final paint factors */
+                       if (closest_id[1] != -1) {
+                               float neigh_diff = dot_v3v3(bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir);
+                               /* linearize both values */
+                               neigh_diff *= neigh_diff;
+                               closest_d[0] *= closest_d[0];
+
+                               /* get relation to angle between neighs */
+                               closest_d[0] -= neigh_diff;
+                               /* and normalize as relative angle within neigh range */
+                               closest_d[0] /= 1.0f - neigh_diff;
+
+                               /* simply set other neigh to cover missing half of this factor */
+                               closest_d[1] = 1.0f - closest_d[0];
+                       }
+                       else if (closest_id[0] != -1) {
+                               /* if only one neigh, still linearize to minimize spread */
+                               closest_d[0] *= closest_d[0];
+                       }
 
-                                               /* just skip if angle is too extreme */
-                                               if (dir_dot <= 0.0f) continue;
 
-                                               /* adjust drip speed depending on wetness */
-                                               w_factor = pPoint->wetness*0.4 - 0.05f;
-                                               if (w_factor <= 0) continue;
-                                               w_factor *= w_factor;
+                       /* Apply movement towards those two points */
+                       for (i=0; i<2; i++) {
+                               int n_index = closest_id[i];
+                               if (n_index != -1 && closest_d[i]>0.0f) {
+                                       float dir_dot = closest_d[i], dir_factor;
+                                       float speed_scale = eff_scale*force[index*4+3]/bNeighs[n_index].dist;
+                                       PaintPoint *ePoint = &((PaintPoint*)sData->type_data)[sData->adj_data->n_target[n_index]];
 
-                                               dir_factor = dir_dot * speed_scale * w_factor;
-                                               if (dir_factor > 1.0f) dir_factor = 1.0f;
+                                       /* just skip if angle is too extreme */
+                                       if (dir_dot <= 0.0f) continue;
 
-                                               /* mix new color */
-                                               mixColors(ePoint->e_color, ePoint->e_alpha, pPoint->e_color, dir_factor);
+                                       dir_factor = dir_dot * speed_scale * w_factor;
+                                       if (dir_factor > 1.0f) dir_factor = 1.0f;
 
-                                               ePoint->e_alpha += dir_factor;
-                                               ePoint->wetness += dir_factor;
-                                               if (ePoint->e_alpha > 1.0f) ePoint->e_alpha = 1.0f;
+                                       /* mix new color */
+                                       mixColors(ePoint->e_color, ePoint->e_alpha, pPoint->e_color, dir_factor);
 
-                                               /* and decrease paint wetness on current point */
-                                               pPoint->wetness -= dir_factor;
-                                       }
+                                       ePoint->e_alpha += dir_factor;
+                                       ePoint->wetness += dir_factor;
+                                       if (ePoint->e_alpha > 1.0f) ePoint->e_alpha = 1.0f;
+
+                                       /* and decrease paint wetness on current point */
+                                       pPoint->wetness -= dir_factor;
                                }
                        }
-               MEM_freeN(str);
                }
 
                /* Keep values within acceptable range */
@@ -3332,6 +3460,113 @@ static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, EffBakeNPoin
        }
 }
 
+#define WAVE_TIME_FAC 0.1
+
+void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, BakeNeighPoint *bNeighs, float timescale)
+{
+       PaintSurfaceData *sData = surface->data;
+       int index;
+       int steps, ss;
+       float dt, min_dist, damp_factor;
+       float wave_speed = surface->wave_speed;
+       double average_dist = 0.0f;
+
+       /* allocate memory */
+       PaintWavePoint *prevPoint = MEM_mallocN(sData->total_points*sizeof(PaintWavePoint), "Temp previous points for wave simulation");
+       if (!prevPoint) return;
+
+       /* calculate average neigh distance (single thread) */
+       for (index = 0; index < sData->total_points; index++)
+       {
+               int i;
+               int numOfNeighs = sData->adj_data->numOf_n[index];
+
+               for (i=0; i<numOfNeighs; i++) {
+                       average_dist += bNeighs[sData->adj_data->n_index[index]+i].dist;
+               }
+       }
+       average_dist  /= sData->adj_data->total_targets;
+
+       /* determine number of required steps */
+       steps = ceil((WAVE_TIME_FAC*timescale*surface->wave_timescale) / (average_dist/wave_speed/3));
+       CLAMP(steps, 1, 15);
+       timescale /= steps;
+
+       /* apply simulation values for final timescale */
+       dt = WAVE_TIME_FAC*timescale*surface->wave_timescale;
+       min_dist = wave_speed*dt*1.5f;
+       damp_factor = pow((1.0f-surface->wave_damping), 1.0f*timescale);
+
+       for (ss=0; ss<steps; ss++) {
+
+               /* copy previous frame data */
+               memcpy(prevPoint, sData->type_data, sData->total_points*sizeof(PaintWavePoint));
+
+               #pragma omp parallel for schedule(static)
+               for (index = 0; index < sData->total_points; index++) {
+                       PaintWavePoint *wPoint = &((PaintWavePoint*)sData->type_data)[index];
+                       int numOfNeighs = sData->adj_data->numOf_n[index];
+                       float force = 0.0f, avg_dist = 0.0f, avg_height = 0.0f;
+                       int numOfN = 0, numOfRN = 0;
+                       int i;
+
+                       if (wPoint->state) continue;
+
+                       /* calculate force from surrounding points */
+                       for (i=0; i<numOfNeighs; i++) {
+                               int n_index = sData->adj_data->n_index[index]+i;
+                               float dist = bNeighs[n_index].dist;
+                               PaintWavePoint *tPoint = &prevPoint[sData->adj_data->n_target[n_index]];
+
+                               if (!dist || tPoint->state) continue;
+                               if (dist<min_dist) dist=min_dist;
+                               avg_dist += dist;
+                               numOfN++;
+
+                               /* count average height for edge points for open borders */
+                               if (!(sData->adj_data->flags[sData->adj_data->n_target[n_index]] & ADJ_ON_MESH_EDGE)) {
+                                       avg_height += tPoint->height;
+                                       numOfRN++;
+                               }
+
+                               force += (tPoint->height - wPoint->height) / (dist*dist);
+                       }
+                       avg_dist = (numOfN) ? avg_dist/numOfN : 0.0f;
+
+                       if (surface->flags & MOD_DPAINT_WAVE_OPEN_BORDERS &&
+                               sData->adj_data->flags[index] & ADJ_ON_MESH_EDGE) {
+
+                               /* if open borders, apply a fake height to keep waves going on */
+                               avg_height = (numOfRN) ? avg_height/numOfRN : 0.0f;
+
+                               wPoint->height = (dt*wave_speed*avg_height + wPoint->height*avg_dist) / (avg_dist + dt*wave_speed);
+                       }
+                       /* else, do wave eq */
+                       else {
+                               /* add force towards zero height based on average dist */
+                               if (avg_dist)
+                                       force += (0.0f - wPoint->height) * surface->wave_spring / (avg_dist*avg_dist) / 2.0f;
+
+                               /* change point velocity */
+                               wPoint->velocity += force*dt * wave_speed*wave_speed;
+                               /* damping */
+                               wPoint->velocity *= damp_factor;
+
+                               /* and new height */
+                               wPoint->height += wPoint->velocity*dt;
+                       }
+               }
+       }
+
+       /* reset d_obs and state */ 
+       for (index = 0; index < sData->total_points; index++) {
+               PaintWavePoint *wPoint = &((PaintWavePoint*)sData->type_data)[index];
+               wPoint->state = 0;
+       }
+
+       MEM_freeN(prevPoint);
+}
+
 #define VALUE_DISSOLVE(VALUE, SPEED, SCALE, LOG) (VALUE) = (LOG) ? (VALUE) * 1.0f - 1.0f/((SPEED)/(SCALE)) : (VALUE) - 1.0f/(SPEED)*(SCALE)
 
 /* Prepare for surface step by creating PaintBakePoint data */
@@ -3483,7 +3718,8 @@ static int dynamicPaint_prepareSurfaceStep(DynamicPaintSurface *surface, PaintBa
                }
 
                /* Prepare special data for surface types */
-               if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
+               if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
+                       surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
                        float temp_nor[3];
                        if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX)
                                {normal_short_to_float_v3(temp_nor, mvert[index].no);
@@ -3657,45 +3893,58 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
 
        MEM_freeN(bData.bPoint);
 
-       /* paint movement effects */
-       if (surface->effect && surface->type == MOD_DPAINT_SURFACE_T_PAINT && sData->eff_data)
+       /* neighbour data and surface opretions that use it */
+       if (sData->adj_data)
        {
-               int steps = 1, s;
-               PaintPoint *prevPoint;
-               EffBakeNPoint *eNeighs;
-               float *force = NULL;
+               BakeNeighPoint *bNeighs = MEM_mallocN(sData->adj_data->total_targets*sizeof(struct BakeNeighPoint), "PaintEffectBake");
 
-               /* free antialias sample coords, as theyre not needed anymore */
-               if (sData->samples>1) bData.realCoord = MEM_reallocN(bData.realCoord, sData->total_points*3*sizeof(float));
-               /* neighbouring point distances and dirs */
-               eNeighs = MEM_mallocN(sData->eff_data->total_targets*sizeof(struct EffBakeNPoint), "PaintEffectBake");
-               /* Allocate memory for surface previous points to read unchanged values from    */
-               prevPoint = MEM_mallocN(sData->total_points*sizeof(struct PaintPoint), "PaintSurfaceDataCopy");
+               if (bNeighs) {
+                       /* calculate current frame distances and global dirs */
+                       dynamicPaint_prepareNeighbourData(surface, bNeighs, bData.realCoord);
 
-               /* in case of error, free already allocated blocks */
-               if (!prevPoint || !eNeighs || !bData.realCoord) {
-                       if (!bData.realCoord) MEM_freeN(bData.realCoord);
-                       if (!eNeighs) MEM_freeN(eNeighs);
-                       if (!prevPoint) MEM_freeN(prevPoint);
+                       /* wave type surface simulation step */
+                       if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
+                               dynamicPaint_doWaveStep(surface, bNeighs, timescale);
+                       }
 
-                       return printError(canvas, "Not enough free memory.");
-               }
+                       /* paint movement effects */
+                       if (surface->effect && surface->type == MOD_DPAINT_SURFACE_T_PAINT)
+                       {
+                               int steps = 1, s;
+                               PaintPoint *prevPoint;
+                               float *force = NULL;
 
-               /* Prepare effects and get number of required steps */
-               steps = dynamicPaint_prepareEffectStep(surface, scene, ob, eNeighs, &force, bData.realCoord, timescale);
+                               /* free antialias sample coords, as theyre not needed anymore */
+                               if (sData->samples>1) bData.realCoord = MEM_reallocN(bData.realCoord, sData->total_points*3*sizeof(float));
+                               /* Allocate memory for surface previous points to read unchanged values from    */
+                               prevPoint = MEM_mallocN(sData->total_points*sizeof(struct PaintPoint), "PaintSurfaceDataCopy");
 
-               /*
-               *       Do Effects steps
-               */
-               for (s = 0; s < steps; s++)
-               {
-                       dynamicPaint_doEffectStep(surface, eNeighs, force, prevPoint, timescale/(float)steps);
-               }
+                               /* in case of error, free already allocated blocks */
+                               if (!prevPoint || !bData.realCoord) {
+                                       if (!bData.realCoord) MEM_freeN(bData.realCoord);
+                                       if (!prevPoint) MEM_freeN(prevPoint);
+
+                                       return printError(canvas, "Not enough free memory.");
+                               }
+
+                               /* Prepare effects and get number of required steps */
+                               steps = dynamicPaint_prepareEffectStep(surface, scene, ob, bNeighs, &force, bData.realCoord, timescale);
 
-               /* Free temporary effect data   */
-               if (eNeighs) MEM_freeN(eNeighs);
-               if (prevPoint) MEM_freeN(prevPoint);
-               if (force) MEM_freeN(force);
+                               /*
+                               *       Do Effects steps
+                               */
+                               for (s = 0; s < steps; s++)
+                               {
+                                       dynamicPaint_doEffectStep(surface, bNeighs, force, prevPoint, timescale/(float)steps);
+                               }
+
+                               /* Free temporary effect data   */
+                               if (prevPoint) MEM_freeN(prevPoint);
+                               if (force) MEM_freeN(force);
+                       }
+
+                       MEM_freeN(bNeighs);
+               }
        }
 
        MEM_freeN(bData.realCoord);
@@ -3830,10 +4079,16 @@ static int dynamicPaint_bakeImageSequence(bContext *C, DynamicPaintSurface *surf
                        }
 
                        /* displacement map     */
-                       if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
+                       else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
                                sprintf(filename, "%s%s%s%s%i", surface->image_output_path, dir_slash, surface->output_name, pad, (int)frame);
                                dynamicPaint_outputImage(surface, filename, format, DPOUTPUT_DISPLACE);
                        }
+
+                       /* waves        */
+                       else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
+                               sprintf(filename, "%s%s%s%s%i", surface->image_output_path, dir_slash, surface->output_name, pad, (int)frame);
+                               dynamicPaint_outputImage(surface, filename, format, DPOUTPUT_WAVES);
+                       }
                }
        }
        return 1;
index 65e16f53b3d6ebf8b72ebc4c902e2ceeac4bf92a..71aeee9c2347f32c093506e36f1bd65e52700a20 100644 (file)
@@ -683,17 +683,17 @@ static int  ptcache_dynamicpaint_write(PTCacheFile *pf, void *dp_v)
                /* cache type */
                ptcache_file_write(pf, &surface->type, 1, sizeof(int));
 
-               if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+               if (surface->type == MOD_DPAINT_SURFACE_T_PAINT)
                        in_len = sizeof(PaintPoint)*total_points;
-                       out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len), "pointcache_lzo_buffer");
-               }
                else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
-                                surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
+                                surface->type == MOD_DPAINT_SURFACE_T_WEIGHT)
                        in_len = sizeof(float)*total_points;
-                       out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len), "pointcache_lzo_buffer");
-               }
+               if (surface->type == MOD_DPAINT_SURFACE_T_WAVE)
+                       in_len = sizeof(PaintWavePoint)*total_points;
                else return 0;
 
+               out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len), "pointcache_lzo_buffer");
+
                ptcache_file_compressed_write(pf, (unsigned char *)surface->data->type_data, in_len, out, cache_compress);
                MEM_freeN(out);
 
@@ -725,6 +725,8 @@ static int ptcache_dynamicpaint_read(PTCacheFile *pf, void *dp_v)
                else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
                                 surface->type == MOD_DPAINT_SURFACE_T_WEIGHT)
                        data_len = sizeof(float);
+               if (surface->type == MOD_DPAINT_SURFACE_T_WAVE)
+                       data_len = sizeof(PaintWavePoint);
                else return 0;
 
                ptcache_file_compressed_read(pf, (unsigned char*)surface->data->type_data, data_len*surface->data->total_points);
@@ -2413,7 +2415,7 @@ int  BKE_ptcache_id_reset(Scene *scene, PTCacheID *pid, int mode)
                else if(pid->type == PTCACHE_TYPE_SMOKE_HIGHRES)
                        smokeModifier_reset_turbulence(pid->calldata);
                else if(pid->type == PTCACHE_TYPE_DYNAMICPAINT)
-                       dynamicPaint_resetSurface((DynamicPaintSurface*)pid->calldata);
+                       dynamicPaint_clearSurface((DynamicPaintSurface*)pid->calldata);
        }
        if(clear)
                BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
index 3ec8c9d5fd65748a31d210853aa2863812c9c4af..92626650b87f5646e7b774c58344268ccf11976e 100644 (file)
@@ -26,7 +26,7 @@ struct PaintSurfaceData;
 #define MOD_DPAINT_SURFACE_T_PAINT 0
 #define MOD_DPAINT_SURFACE_T_DISPLACE 1
 #define MOD_DPAINT_SURFACE_T_WEIGHT 2
-#define MOD_DPAINT_SURFACE_T_IWAVE 3
+#define MOD_DPAINT_SURFACE_T_WAVE 3
 
 /* surface flags */
 #define MOD_DPAINT_ACTIVE (1<<0) /* Is surface enabled */
@@ -36,10 +36,10 @@ struct PaintSurfaceData;
 #define MOD_DPAINT_MULALPHA (1<<3) /* Multiply color by alpha when saving image */
 #define MOD_DPAINT_DISSOLVE_LOG (1<<4) /* Use 1/x for surface dissolve */
 #define MOD_DPAINT_DRY_LOG (1<<5) /* Use 1/x for drying paint */
-
 #define MOD_DPAINT_PREVIEW (1<<6) /* preview this surface on viewport*/
 
-/* image sequence output */
+#define MOD_DPAINT_WAVE_OPEN_BORDERS (1<<7) /* passes waves through mesh edges */
+
 #define MOD_DPAINT_OUT1 (1<<10) /* output primary surface */
 #define MOD_DPAINT_OUT2 (1<<11) /* output secondary surface */
 
@@ -88,7 +88,11 @@ typedef struct DynamicPaintSurface {
        int dry_speed, diss_speed;
        float disp_depth;
 
-       float spread_speed, shrink_speed, pad_f;
+       float spread_speed, shrink_speed;
+
+       /* wave settings */
+       float wave_damping, wave_speed, wave_timescale, wave_spring;
+       float pad_f;
        char uvlayer_name[32];
 
        char image_output_path[240];
@@ -123,7 +127,6 @@ typedef struct DynamicPaintCanvasSettings {
 #define MOD_DPAINT_RAMP_ALPHA (1<<4) /* only read falloff ramp alpha */
 #define MOD_DPAINT_PROX_FACEALIGNED (1<<5) /* do proximity check only in normal dir */
 #define MOD_DPAINT_INVERSE_PROX (1<<6) /* inverse proximity painting */
-//#define MOD_DPAINT_EDGE_DISP (1<<6) /* add displacement to intersection edges */
 
 /* collision type */
 #define MOD_DPAINT_COL_VOLUME 0 /* paint with mesh volume */
@@ -136,6 +139,11 @@ typedef struct DynamicPaintCanvasSettings {
 #define MOD_DPAINT_PRFALL_SMOOTH 1 /* smooth, linear falloff */
 #define MOD_DPAINT_PRFALL_RAMP 2 /* use color ramp */
 
+/* wave_brush_type */
+#define MOD_DPAINT_WAVEB_DEPTH 0 /* use intersection depth */
+#define MOD_DPAINT_WAVEB_FORCE 1 /* act as a force on intersection area */
+#define MOD_DPAINT_WAVEB_REFLECT 2 /* obstacle that reflects waves */
+
 
 /* Painter settings */
 typedef struct DynamicPaintBrushSettings {
@@ -159,9 +167,11 @@ typedef struct DynamicPaintBrushSettings {
 
        short proximity_falloff;
        short brush_settings_context;   /* ui settings display */
-       int pad2;       // replace if need for new value
+       short wave_type;
+       short pad_s;
 
-       //int pad;
+       float wave_factor;
+       float pad_f;
 } DynamicPaintBrushSettings;
 
 #endif
index 0b0450d62a8ab835b56c1d15ff72f1f352d52827..d89df053a30f423ffb711ff7531daba2a4be1b1a 100644 (file)
@@ -220,14 +220,13 @@ static EnumPropertyItem *rna_DynamicPaint_surface_type_itemf(bContext *C, Pointe
                RNA_enum_item_add(&item, &totitem, &tmp);
        }
 
-       /* iWave */
-       /*if (surface->format == MOD_DPAINT_SURFACE_F_PTEX ||
-               surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
-               tmp.value = MOD_DPAINT_SURFACE_T_IWAVE;
-               tmp.identifier = "IWAVE";
-               tmp.name = "iWave";
+       /* Height waves */
+       {
+               tmp.value = MOD_DPAINT_SURFACE_T_WAVE;
+               tmp.identifier = "WAVE";
+               tmp.name = "Waves";
                RNA_enum_item_add(&item, &totitem, &tmp);
-       }*/
+       }
 
        RNA_enum_item_end(&item, &totitem);
        *free = 1;
@@ -507,6 +506,35 @@ static void rna_def_canvas_surface(BlenderRNA *brna)
        RNA_def_property_enum_items(prop, prop_dynamicpaint_disp_type);
        RNA_def_property_ui_text(prop, "Data Type", "");
 
+       /* wave simulator settings */
+       prop= RNA_def_property(srna, "wave_damping", PROP_FLOAT, PROP_NONE);
+       RNA_def_property_float_sdna(prop, NULL, "wave_damping");
+       RNA_def_property_range(prop, 0.001, 1.0);
+       RNA_def_property_ui_range(prop, 0.01, 1.0, 1, 2);
+       RNA_def_property_ui_text(prop, "Damping", "Wave damping factor.");
+
+       prop= RNA_def_property(srna, "wave_speed", PROP_FLOAT, PROP_NONE);
+       RNA_def_property_float_sdna(prop, NULL, "wave_speed");
+       RNA_def_property_range(prop, 0.01, 3.0);
+       RNA_def_property_ui_range(prop, 0.01, 1.5, 1, 2);
+       RNA_def_property_ui_text(prop, "Speed", "Wave speed.");
+
+       prop= RNA_def_property(srna, "wave_timescale", PROP_FLOAT, PROP_NONE);
+       RNA_def_property_float_sdna(prop, NULL, "wave_timescale");
+       RNA_def_property_range(prop, 0.01, 3.0);
+       RNA_def_property_ui_range(prop, 0.01, 1.5, 1, 2);
+       RNA_def_property_ui_text(prop, "Timescale", "Wave time scaling factor.");
+
+       prop= RNA_def_property(srna, "wave_spring", PROP_FLOAT, PROP_NONE);
+       RNA_def_property_float_sdna(prop, NULL, "wave_spring");
+       RNA_def_property_range(prop, 0.01, 1.0);
+       RNA_def_property_ui_range(prop, 0.01, 1.0, 1, 2);
+       RNA_def_property_ui_text(prop, "Spring", "Spring force that pulls water level back to zero.");
+
+       prop= RNA_def_property(srna, "wave_open_borders", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DPAINT_WAVE_OPEN_BORDERS);
+       RNA_def_property_ui_text(prop, "Open Borders", "Passes waves through mesh edges.");
+
        
        /* cache */
        prop= RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE);
@@ -565,10 +593,16 @@ static void rna_def_dynamic_paint_brush_settings(BlenderRNA *brna)
                        {MOD_DPAINT_PRFALL_RAMP, "RAMP", 0, "Color Ramp", ""},
                        {0, NULL, 0, NULL, NULL}};
 
+       static EnumPropertyItem prop_dynamicpaint_brush_wave_type[] = {
+                       {MOD_DPAINT_WAVEB_DEPTH, "DEPTH", 0, "Obstacle", ""},
+                       {MOD_DPAINT_WAVEB_FORCE, "FORCE", 0, "Force", ""},
+                       {MOD_DPAINT_WAVEB_REFLECT, "REFLECT", 0, "Reflect Only", ""},
+                       {0, NULL, 0, NULL, NULL}};
+
        static EnumPropertyItem buttons_dynamicpaint_settings_menu[] = {
                {0, "GENERAL", ICON_MOD_DYNAMICPAINT, "", "Show general settings"},
-               {1, "DISPLACE", ICON_MOD_DISPLACE, "", "Show displace related settings"},
-               {3, "IWAVE", ICON_MOD_WAVE, "", "Show iWave related settings"},
+               //{1, "DISPLACE", ICON_MOD_DISPLACE, "", "Show displace related settings"},
+               {2, "WAVE", ICON_MOD_WAVE, "", "Show wave related settings"},
                {0, NULL, 0, NULL, NULL}};
 
        srna = RNA_def_struct(brna, "DynamicPaintBrushSettings", NULL);
@@ -618,6 +652,18 @@ static void rna_def_dynamic_paint_brush_settings(BlenderRNA *brna)
        prop= RNA_def_property(srna, "paint_erase", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DPAINT_ERASE);
        RNA_def_property_ui_text(prop, "Erase Paint", "Erase / remove paint instead of adding it.");
+
+       prop= RNA_def_property(srna, "wave_type", PROP_ENUM, PROP_NONE);
+       RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+       RNA_def_property_enum_sdna(prop, NULL, "wave_type");
+       RNA_def_property_enum_items(prop, prop_dynamicpaint_brush_wave_type);
+       RNA_def_property_ui_text(prop, "Paint Type", "");
+
+       prop= RNA_def_property(srna, "wave_factor", PROP_FLOAT, PROP_NONE);
+       RNA_def_property_float_sdna(prop, NULL, "wave_factor");
+       RNA_def_property_range(prop, -2.0, 2.0);
+       RNA_def_property_ui_range(prop, -1.0, 1.0, 1, 2);
+       RNA_def_property_ui_text(prop, "Factor", "Multiplier for wave strenght of this brush.");
        
        /*
        *   Paint Area / Collision