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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiika Hamalainen <blender@miikah.org>2011-06-27 11:30:58 +0400
committerMiika Hamalainen <blender@miikah.org>2011-06-27 11:30:58 +0400
commitcb12648656fc001e8c4c6d00df73e52d452f8787 (patch)
tree95e01261ef1c1f5d0e7e4880602858827713921c
parent40d4f34e82338b98d05595175504120fd98ae680 (diff)
Dynamic Paint:
* Fixed memory leak when baking image sequences. * Fixed sub-steps when brush was controlled by a parent object. * Added option to select active outputs for paint surfaces. * Improved color mixing algorithm. * Improved memory allocation behavior. * Memory is now freed even in case of errors. * Removed "initial color" setting, as it's better to adjust color from material. * "Paint effects" system: ** Converted to use new data structures. ** Works now with any number of surrounding points. ** Re-implemented support for UV-image surfaces. ** Added support for vertex surfaces too. ** Improved color handling. ** Improved movement stability. ** "Drip" effect uses now Blender's force fields instead of just z-directional gravity like before. Now each surface point can have different force influence.
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py23
-rw-r--r--source/blender/blenkernel/BKE_dynamicpaint.h4
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c1471
-rw-r--r--source/blender/blenloader/intern/readfile.c3
-rw-r--r--source/blender/blenloader/intern/writefile.c7
-rw-r--r--source/blender/makesdna/DNA_dynamicpaint_types.h8
-rw-r--r--source/blender/makesrna/intern/rna_dynamicpaint.c34
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c16
8 files changed, 1074 insertions, 492 deletions
diff --git a/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py b/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py
index 9f3f5902ad3..52945ab7e11 100644
--- a/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py
+++ b/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py
@@ -21,6 +21,7 @@ import bpy
from bl_ui.properties_physics_common import (
point_cache_ui,
+ effector_weights_ui,
)
class PhysicButtonsPanel():
@@ -123,9 +124,9 @@ class PHYSICS_PT_dp_advanced_canvas(PhysicButtonsPanel, bpy.types.Panel):
ob = context.object
layout.prop(surface, "surface_type", expand=False)
+ layout.separator()
if (surface.surface_type == "PAINT"):
- layout.prop(surface, "initial_color", expand=False)
split = layout.split(percentage=0.8)
split.prop(surface, "dry_speed", text="Dry Time")
split.prop(surface, "use_dry_log", text="Slow")
@@ -189,15 +190,21 @@ class PHYSICS_PT_dp_canvas_output(PhysicButtonsPanel, bpy.types.Panel):
col = layout.column()
col.prop(surface, "image_output_path", text="Output directory")
+ col.prop(surface, "image_fileformat", text="Image Format:")
if (surface.surface_type == "PAINT"):
- col.prop(surface, "output_name", text="Paintmap: ")
- col.prop(surface, "premultiply", text="Premultiply alpha")
- col.prop(surface, "output_name2", text="Wetmap: ")
+ col.prop(surface, "do_output1", text="Output Paintmaps:")
+ sub = col.column()
+ sub.active = surface.do_output1
+ sub.prop(surface, "output_name", text="Filename: ")
+ sub.prop(surface, "premultiply", text="Premultiply alpha")
+
+ col.prop(surface, "do_output2", text="Output Wetmaps:")
+ sub = col.column()
+ sub.active = surface.do_output2
+ sub.prop(surface, "output_name2", text="Filename: ")
if (surface.surface_type == "DISPLACE"):
col.prop(surface, "output_name", text="Filename: ")
col.prop(surface, "disp_type", text="Displace Type")
-
- col.prop(surface, "image_fileformat", text="Image Format:")
layout.separator()
layout.operator("dpaint.bake", text="Bake Image Sequence", icon='MOD_DYNAMICPAINT')
@@ -215,7 +222,7 @@ class PHYSICS_PT_dp_effects(PhysicButtonsPanel, bpy.types.Panel):
if ((not md) or (md.dynamicpaint_type != 'CANVAS')):
return False;
surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active
- return surface and (surface.surface_format != "VERTEX")
+ return surface and (surface.surface_format != "PTEX")
def draw(self, context):
layout = self.layout
@@ -235,7 +242,7 @@ class PHYSICS_PT_dp_effects(PhysicButtonsPanel, bpy.types.Panel):
layout.prop(surface, "use_drip")
col = layout.column()
col.active = surface.use_drip
- col.prop(surface, "drip_speed")
+ effector_weights_ui(self, context, surface.effector_weights)
elif surface.effect_ui == "SHRINK":
layout.prop(surface, "use_shrink")
diff --git a/source/blender/blenkernel/BKE_dynamicpaint.h b/source/blender/blenkernel/BKE_dynamicpaint.h
index 791f218d4ca..03b64163ce4 100644
--- a/source/blender/blenkernel/BKE_dynamicpaint.h
+++ b/source/blender/blenkernel/BKE_dynamicpaint.h
@@ -16,12 +16,16 @@
#include "DNA_dynamicpaint_types.h"
+struct PaintEffectData;
+
/* Actual surface point */
typedef struct PaintSurfaceData {
/* surface format data */
void *format_data;
/* surface type data */
void *type_data;
+ /* paint effects data */
+ struct PaintEffectData *eff_data;
unsigned int total_points;
short samples;
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 377967c2e87..dbf95135888 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -36,6 +36,7 @@
#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_dynamicpaint.h"
+#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_material.h"
@@ -136,36 +137,49 @@ typedef struct Vec3f {
typedef struct PaintBakePoint {
float invNorm[3]; /* current pixel world-space inverted normal. depends on face shading mode */
float normal_scale; /* normal directional scale for displace mapping */
-
- /*
- * Effect / moving layer data
- * ! Only generated if effects enabled ! */
- float gravity_dir; /* UV space direction of gravity */
- float gravity_rate; /* Gravity strength. (Depends on surface angle.) */
} PaintBakePoint;
typedef struct PaintBakeData {
PaintBakePoint *bPoint;
- float *realCoord; /* current pixel center world-space coordinates * numOfSamples */
+ float *realCoord; /* current pixel center world-space coordinates * numOfSamples
+ * ordered as (total_points*sample+index)*3*/
} PaintBakeData;
/* UV Image sequence format point */
-typedef struct PaintTexturePoint {
-
- int neighbour[8]; /* Indexes of 8 neighbouring pixels if exist */
- float neighbour_dist[8]; /* Distances to all 8 neighbouring pixels */
-
-
+typedef struct PaintUVPoint {
/* Pixel / mesh data */
- int face_index, pixel_index; /* face index on domain derived mesh */
- int v1, v2, v3; /* vertex indexes */
+ unsigned int face_index, pixel_index; /* face index on domain derived mesh */
+ unsigned int v1, v2, v3; /* vertex indexes */
- int neighbour_pixel; /* If this pixel isn't uv mapped to any face,
+ unsigned int neighbour_pixel; /* If this pixel isn't uv mapped to any face,
but it's neighbouring pixel is */
short quad;
- struct Vec3f *barycentricWeights; /* b-weights for all pixel samples */
-
-} PaintTexturePoint;
+} PaintUVPoint;
+
+typedef struct ImgSeqFormatData {
+ PaintUVPoint *uv_p;
+ Vec3f *barycentricWeights; /* b-weights for all pixel samples */
+} ImgSeqFormatData;
+
+typedef struct EffVelPoint {
+ float previous_pos[3];
+ float previous_vel[3];
+} EffVelPoint;
+
+typedef struct EffBakeNPoint {
+ float dir[3]; /* vector pointing towards this neighbour */
+ float dist; /* distance to */
+} EffBakeNPoint;
+
+typedef struct PaintEffectData {
+ 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 total_targets; /* size of n_target */
+ unsigned int most_neighs;
+ //EffVelPoint *v_point;
+} PaintEffectData;
/***************************** General Utils ******************************/
@@ -301,6 +315,24 @@ void dynamicPaintSurface_setUniqueName(DynamicPaintSurface *surface, char *basen
BLI_uniquename_cb(surfaceDublicateNameExists, surface, name, '.', surface->name, sizeof(surface->name));
}
+/* assumes source alpha > 0.0f */
+static void mixColors(float *t_color, float t_alpha, float *s_color, float s_alpha)
+{
+ float invFact = (s_alpha<t_alpha) ? 1.0f : t_alpha/s_alpha;
+ float factor = 1.0f - invFact;
+ /* set initial color depending on existing alpha */
+ t_color[0] = t_color[0]*invFact + s_color[0]*factor;
+ t_color[1] = t_color[1]*invFact + s_color[1]*factor;
+ t_color[2] = t_color[2]*invFact + s_color[2]*factor;
+
+ /* mix final color */
+ factor = s_alpha;
+ invFact = 1.0f - factor;
+ t_color[0] = t_color[0]*invFact + s_color[0]*factor;
+ t_color[1] = t_color[1]*invFact + s_color[1]*factor;
+ t_color[2] = t_color[2]*invFact + s_color[2]*factor;
+}
+
/***************************** Freeing data ******************************/
/* Free brush data */
@@ -320,14 +352,33 @@ 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);
+ }
+}
+
static void dynamicPaint_freeSurfaceData(DynamicPaintSurface *surface)
{
PaintSurfaceData *data = surface->data;
if (!data) return;
-
- if (data->format_data) MEM_freeN(data->format_data);
+ if (data->format_data) {
+ /* format specific free */
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
+ ImgSeqFormatData *format_data = (ImgSeqFormatData*)data->format_data;
+ if (format_data->uv_p)
+ MEM_freeN(format_data->uv_p);
+ if (format_data->barycentricWeights)
+ MEM_freeN(format_data->barycentricWeights);
+ }
+ MEM_freeN(data->format_data);
+ }
if (data->type_data) MEM_freeN(data->type_data);
-
+ dynamicPaint_freeEffectData(data);
MEM_freeN(surface->data);
surface->data = NULL;
}
@@ -340,6 +391,10 @@ static void dynamicPaint_freeSurface(DynamicPaintSurface *surface)
BKE_ptcache_free_list(&(surface->ptcaches));
surface->pointcache = NULL;
+ if(surface->effector_weights)
+ MEM_freeN(surface->effector_weights);
+ surface->effector_weights = NULL;
+
BLI_remlink(&(surface->canvas->surfaces), surface);
dynamicPaint_freeSurfaceData(surface);
MEM_freeN(surface);
@@ -400,7 +455,8 @@ static DynamicPaintSurface *dynamicPaint_createNewSurface(DynamicPaintCanvasSett
surface->pointcache->step = 1;
/* Set initial values */
- surface->flags = MOD_DPAINT_ANTIALIAS | MOD_DPAINT_MULALPHA | MOD_DPAINT_DRY_LOG | MOD_DPAINT_DISSOLVE_LOG | MOD_DPAINT_ACTIVE | MOD_DPAINT_PREVIEW;
+ surface->flags = MOD_DPAINT_ANTIALIAS | MOD_DPAINT_MULALPHA | MOD_DPAINT_DRY_LOG | MOD_DPAINT_DISSOLVE_LOG |
+ MOD_DPAINT_ACTIVE | MOD_DPAINT_PREVIEW | MOD_DPAINT_OUT1;
surface->effect = 0;
surface->effect_ui = 1;
@@ -416,12 +472,13 @@ static DynamicPaintSurface *dynamicPaint_createNewSurface(DynamicPaintCanvasSett
surface->substeps = 0;
surface->spread_speed = 1.0f;
- surface->drip_speed = 1.0f;
surface->shrink_speed = 1.0f;
sprintf(surface->image_output_path, "%sdynamicpaint/", "/tmp/");
dynamicPaintSurface_setUniqueName(surface, "Surface");
+ surface->effector_weights = BKE_add_effector_weights(NULL);
+
dynamicPaintSurface_updateType(surface);
BLI_addtail(&canvas->surfaces, surface);
@@ -461,7 +518,7 @@ void dynamicPaint_Modifier_createType(struct DynamicPaintModifierData *pmd)
pmd->brush->psys = NULL;
- pmd->brush->flags = 0;
+ pmd->brush->flags = MOD_DPAINT_ABS_ALPHA;
pmd->brush->collision = MOD_DPAINT_COL_VOLUME;
pmd->brush->mat = NULL;
@@ -584,17 +641,77 @@ static void dynamicPaint_allocateSurfaceType(DynamicPaintSurface *surface)
}
else return;
- if (sData->type_data == NULL) printError(surface->canvas, "Not enough memory!");
+ if (sData->type_data == NULL) printError(surface->canvas, "Not enough free memory!");
}
-static void dynamicPaint_surfaceSetInitialValues(DynamicPaintSurface *surface) {
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- PaintPoint* pPoint = (PaintPoint*)surface->data->type_data;
- int i;
- for (i=0; i<surface->data->total_points; i++) {
- memcpy(pPoint[i].color, surface->intitial_color, sizeof(float)*4);
+
+/* initialize "paint effect" data */
+static void dynamicPaint_initEffectData(DynamicPaintSurface *surface) {
+ PaintSurfaceData *sData = surface->data;
+ PaintEffectData *ed;
+ int neigh_points = 0;
+
+ if (!surface->effect) return;
+
+ if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+ /* For vertex format, neighbours are connected by edges */
+ neigh_points = 2*surface->canvas->dm->getNumEdges(surface->canvas->dm);
+ }
+ else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
+ neigh_points = sData->total_points*8;
+
+ if (!neigh_points) return;
+
+ /* allocate memory */
+ ed = sData->eff_data = MEM_callocN(sizeof(PaintEffectData), "Surface Effect 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->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) {
+ dynamicPaint_freeEffectData(sData);
+ printError(surface->canvas, "Not enough free memory.");
+ return;
+ }
+
+ if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+ int i,j;
+ int n_pos;
+
+ /* For vertex format, count every vertex that is connected by an edge */
+ int numOfEdges = surface->canvas->dm->getNumEdges(surface->canvas->dm);
+ struct MEdge *edge = surface->canvas->dm->getEdgeArray(surface->canvas->dm);
+
+ /* add neighbour data */
+ n_pos = 0;
+ for (i=0; i<sData->total_points; i++) {
+ ed->n_index[i] = n_pos;
+ ed->numOf_n[i] = 0;
+
+ 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];
}
}
+ else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
+ /* for image sequences, only allocate memory.
+ * bake initialization takes care of rest */
+ }
}
/* (re)initialize surface data (only for point cache types)*/
@@ -615,7 +732,7 @@ int dynamicPaint_resetSurface(DynamicPaintSurface *surface)
surface->data->total_points = numOfPoints;
surface->data->samples = 1;
dynamicPaint_allocateSurfaceType(surface);
- dynamicPaint_surfaceSetInitialValues(surface);
+ dynamicPaint_initEffectData(surface);
return 1;
}
@@ -748,20 +865,14 @@ struct DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, S
#pragma omp parallel for schedule(static)
for (i=0; i<surface->data->total_points; i++) {
int j=i*4;
- /* If dry layer already has a color, blend it */
- if (pPoint[i].alpha) {
- float invAlpha = 1.0f - pPoint[i].e_alpha;
- fcolor[j] = pPoint[i].color[0] * invAlpha + pPoint[i].e_color[0] * pPoint[i].e_alpha;
- fcolor[j+1] = pPoint[i].color[1] * invAlpha + pPoint[i].e_color[1] * pPoint[i].e_alpha;
- fcolor[j+2] = pPoint[i].color[2] * invAlpha + pPoint[i].e_color[2] * pPoint[i].e_alpha;
- }
- else {
- /* Else use effect layer color */
- fcolor[j] = pPoint[i].e_color[0];
- fcolor[j+1] = pPoint[i].e_color[1];
- fcolor[j+2] = pPoint[i].e_color[2];
- }
- /* Set use highest alpha */
+
+ fcolor[j] = pPoint[i].color[0];
+ fcolor[j+1] = pPoint[i].color[1];
+ fcolor[j+2] = pPoint[i].color[2];
+ /* mix colors */
+ if (pPoint[i].e_alpha) mixColors(&fcolor[j], pPoint[i].alpha, pPoint[i].e_color, pPoint[i].e_alpha);
+
+ /* Use highest alpha */
fcolor[j+3] = (pPoint[i].e_alpha > pPoint[i].alpha) ? pPoint[i].e_alpha : pPoint[i].alpha;
}
@@ -960,7 +1071,6 @@ struct DerivedMesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scen
/***************************** Image Sequence / UV Image Canvas Calls ******************************/
-#if 0
/*
* Tries to find the neighbouring pixel in given (uv space) direction.
* Result is used by effect system to move paint on the surface.
@@ -968,7 +1078,7 @@ struct DerivedMesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scen
* px,py : origin pixel x and y
* n_index : lookup direction index (use neighX,neighY to get final index)
*/
-static int dynamicPaint_findNeighbourPixel(DynamicPaintSurface *surface, int px, int py, int n_index)
+static int dynamicPaint_findNeighbourPixel(PaintUVPoint *tempPoints, DerivedMesh *dm, char *uvname, int w, int h, int px, int py, int n_index)
{
/* Note: Current method only uses polygon edges to detect neighbouring pixels.
* -> It doesn't always lead to the optimum pixel but is accurate enough
@@ -976,77 +1086,69 @@ static int dynamicPaint_findNeighbourPixel(DynamicPaintSurface *surface, int px,
*/
int x,y;
- DynamicPaintSurfacePoint *tPoint = NULL;
- DynamicPaintSurfacePoint *cPoint = NULL;
- PaintSurfaceData *sData = surface->data;
+ PaintUVPoint *tPoint = NULL;
+ PaintUVPoint *cPoint = NULL;
+ /* shift position by given n_index */
x = px + neighX[n_index];
y = py + neighY[n_index];
- if (x<0 || x>=surface->image_resolution) return -1;
- if (y<0 || y>=surface->image_resolution) return -1;
+ if (x<0 || x>=w) return -1;
+ if (y<0 || y>=h) return -1;
- tPoint = &((PaintTexturePoint*)sData->format_data)[x+surface->image_resolution*y]; /* UV neighbour */
-
- cPoint = &((PaintTexturePoint*)sData->format_data)[px+surface->image_resolution*py]; /* Origin point */
+ tPoint = &tempPoints[x+w*y]; /* UV neighbour */
+ cPoint = &tempPoints[px+w*py]; /* Origin point */
/*
- * Check if target point is on same face -> mark it as neighbour
+ * Check if shifted point is on same face -> it's a correct neighbour
* (and if it isn't marked as an "edge pixel")
*/
- if ((tPoint->index == cPoint->index) && (tPoint->neighbour_pixel == -1)) {
- /* If it's on the same face, it has to be a correct neighbour */
- return (x+surface->w*y);
- }
-
+ if ((tPoint->face_index == cPoint->face_index) && (tPoint->neighbour_pixel == -1))
+ return (x+w*y);
/*
- * If the uv neighbour is mapped directly to
- * a face -> use this point.
+ * Even if shifted point is on another face
+ * -> use this point.
*
* !! Replace with "is uv faces linked" check !!
* This should work fine as long as uv island
* margin is > 1 pixel.
*/
- if ((tPoint->index != -1) && (tPoint->neighbour_pixel == -1)) {
- return (x+surface->w*y);
+ if ((tPoint->face_index != -1) && (tPoint->neighbour_pixel == -1)) {
+ return (x+w*y);
}
/*
* If we get here, the actual neighbouring pixel
- * points to a non-linked uv face, and we have to find
- * it's "real" neighbour.
+ * is located on a non-linked uv face, and we have to find
+ * it's "real" position.
*
* Simple neighbouring face finding algorithm:
- * - find closest uv edge to that pixel and get
- * the other face connected to that edge on actual mesh
+ * - find closest uv edge to shifted pixel and get
+ * the another face that shares that edge
* - find corresponding position of that new face edge
* in uv space
*
* TODO: Implement something more accurate / optimized?
*/
{
- int numOfFaces = canvas->dm->getNumFaces(canvas->dm);
- MVert *mvert = NULL;
- MFace *mface = NULL;
- MTFace *tface = NULL;
-
- mvert = canvas->dm->getVertArray(canvas->dm);
- mface = canvas->dm->getFaceArray(canvas->dm);
- tface = DM_get_face_data_layer(canvas->dm, CD_MTFACE);
+ 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);
/* Get closest edge to that subpixel on UV map */
{
float pixel[2], dist, t_dist;
- int i, uindex[2], edge1_index, edge2_index, e1_index, e2_index, target_face;
-
+ int i, uindex[2], edge1_index, edge2_index,
+ e1_index, e2_index, target_face;
float closest_point[2], lambda, dir_vec[2];
int target_uv1, target_uv2, final_pixel[2], final_index;
- float (*s_uv1),(*s_uv2), (*t_uv1), (*t_uv2);
+ float *s_uv1, *s_uv2, *t_uv1, *t_uv2;
- pixel[0] = ((float)(px + neighX[n_index]) + 0.5f) / (float)surface->w;
- pixel[1] = ((float)(py + neighY[n_index]) + 0.5f) / (float)surface->h;
+ pixel[0] = ((float)(px + neighX[n_index]) + 0.5f) / (float)w;
+ pixel[1] = ((float)(py + neighY[n_index]) + 0.5f) / (float)h;
/* Get uv indexes for current face part */
if (cPoint->quad) {
@@ -1061,14 +1163,14 @@ static int dynamicPaint_findNeighbourPixel(DynamicPaintSurface *surface, int px,
*/
/* Dist to first edge */
e1_index = cPoint->v1; e2_index = cPoint->v2; edge1_index = uindex[0]; edge2_index = uindex[1];
- dist = dist_to_line_segment_v2(pixel, tface[cPoint->index].uv[edge1_index], tface[cPoint->index].uv[edge2_index]);
+ dist = dist_to_line_segment_v2(pixel, tface[cPoint->face_index].uv[edge1_index], tface[cPoint->face_index].uv[edge2_index]);
/* Dist to second edge */
- t_dist = dist_to_line_segment_v2(pixel, tface[cPoint->index].uv[uindex[1]], tface[cPoint->index].uv[uindex[2]]);
+ t_dist = dist_to_line_segment_v2(pixel, tface[cPoint->face_index].uv[uindex[1]], tface[cPoint->face_index].uv[uindex[2]]);
if (t_dist < dist) {e1_index = cPoint->v2; e2_index = cPoint->v3; edge1_index = uindex[1]; edge2_index = uindex[2]; dist = t_dist;}
/* Dist to third edge */
- t_dist = dist_to_line_segment_v2(pixel, tface[cPoint->index].uv[uindex[2]], tface[cPoint->index].uv[uindex[0]]);
+ t_dist = dist_to_line_segment_v2(pixel, tface[cPoint->face_index].uv[uindex[2]], tface[cPoint->face_index].uv[uindex[0]]);
if (t_dist < dist) {e1_index = cPoint->v3; e2_index = cPoint->v1; edge1_index = uindex[2]; edge2_index = uindex[0]; dist = t_dist;}
@@ -1081,12 +1183,11 @@ static int dynamicPaint_findNeighbourPixel(DynamicPaintSurface *surface, int px,
/*
* Check if both edge vertices share this face
*/
- int v4 = -1;
- if (mface[i].v4) v4 = mface[i].v4;
+ int v4 = (mface[i].v4) ? mface[i].v4 : -1;
if ((e1_index == mface[i].v1 || e1_index == mface[i].v2 || e1_index == mface[i].v3 || e1_index == v4) &&
(e2_index == mface[i].v1 || e2_index == mface[i].v2 || e2_index == mface[i].v3 || e2_index == v4)) {
- if (i == cPoint->index) continue;
+ if (i == cPoint->face_index) continue;
target_face = i;
@@ -1113,8 +1214,8 @@ static int dynamicPaint_findNeighbourPixel(DynamicPaintSurface *surface, int px,
/*
* If target face is connected in UV space as well, just use original index
*/
- s_uv1 = (float *)tface[cPoint->index].uv[edge1_index];
- s_uv2 = (float *)tface[cPoint->index].uv[edge2_index];
+ s_uv1 = (float *)tface[cPoint->face_index].uv[edge1_index];
+ s_uv2 = (float *)tface[cPoint->face_index].uv[edge2_index];
t_uv1 = (float *)tface[target_face].uv[target_uv1];
t_uv2 = (float *)tface[target_face].uv[target_uv2];
@@ -1123,13 +1224,13 @@ static int dynamicPaint_findNeighbourPixel(DynamicPaintSurface *surface, int px,
if (((s_uv1[0] == t_uv1[0] && s_uv1[1] == t_uv1[1]) &&
(s_uv2[0] == t_uv2[0] && s_uv2[1] == t_uv2[1]) ) ||
((s_uv2[0] == t_uv1[0] && s_uv2[1] == t_uv1[1]) &&
- (s_uv1[0] == t_uv2[0] && s_uv1[1] == t_uv2[1]) )) return ((px+neighX[n_index]) + surface->w*(py+neighY[n_index]));
+ (s_uv1[0] == t_uv2[0] && s_uv1[1] == t_uv2[1]) )) return ((px+neighX[n_index]) + w*(py+neighY[n_index]));
/*
* Find a point that is relatively at same edge position
* on this other face UV
*/
- lambda = closest_to_line_v2(closest_point, pixel, tface[cPoint->index].uv[edge1_index], tface[cPoint->index].uv[edge2_index]);
+ lambda = closest_to_line_v2(closest_point, pixel, tface[cPoint->face_index].uv[edge1_index], tface[cPoint->face_index].uv[edge2_index]);
if (lambda < 0.0f) lambda = 0.0f;
if (lambda > 1.0f) lambda = 1.0f;
@@ -1139,33 +1240,32 @@ static int dynamicPaint_findNeighbourPixel(DynamicPaintSurface *surface, int px,
copy_v2_v2(pixel, tface[target_face].uv[target_uv1]);
add_v2_v2(pixel, dir_vec);
- pixel[0] = (pixel[0] * (float)surface->w) - 0.5f;
- pixel[1] = (pixel[1] * (float)surface->h) - 0.5f;
+ pixel[0] = (pixel[0] * (float)w) - 0.5f;
+ pixel[1] = (pixel[1] * (float)h) - 0.5f;
final_pixel[0] = (int)floor(pixel[0]);
final_pixel[1] = (int)floor(pixel[1]);
/* If current pixel uv is outside of texture */
- if (final_pixel[0] < 0 || final_pixel[0] >= surface->w) return -1;
- if (final_pixel[1] < 0 || final_pixel[1] >= surface->h) return -1;
+ if (final_pixel[0] < 0 || final_pixel[0] >= w) return -1;
+ if (final_pixel[1] < 0 || final_pixel[1] >= h) return -1;
- final_index = final_pixel[0] + surface->w * final_pixel[1];
+ final_index = final_pixel[0] + w * final_pixel[1];
/* If we ended up to our origin point ( mesh has smaller than pixel sized faces) */
- if (final_index == (px+surface->w*py)) return -1;
+ if (final_index == (px+w*py)) return -1;
/* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
- if (surface->point[final_index].index != target_face) return -1;
+ if (tempPoints[final_index].face_index != target_face) return -1;
/*
* If final point is an "edge pixel", use it's "real" neighbour instead
*/
- if (surface->point[final_index].neighbour_pixel != -1) final_index = cPoint->neighbour_pixel;
+ if (tempPoints[final_index].neighbour_pixel != -1) final_index = cPoint->neighbour_pixel;
return final_index;
}
}
}
-#endif
/*
* Create a surface for image sequence format
@@ -1183,16 +1283,19 @@ static int dynamicPaint_createUVSurface(DynamicPaintSurface *surface)
int numOfFaces;
char uvname[32];
int active_points = 0;
+ int error = 0;
PaintSurfaceData *sData;
DynamicPaintCanvasSettings *canvas = surface->canvas;
DerivedMesh *dm = canvas->dm;
- PaintTexturePoint *tempPoints = NULL;
+ PaintUVPoint *tempPoints = NULL;
+ Vec3f *tempWeights = NULL;
MVert *mvert = NULL;
MFace *mface = NULL;
MTFace *tface = NULL;
BB2d *faceBB = NULL;
+ int *final_index;
if (!dm) return printError(canvas, "Canvas mesh not updated.");
if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ) return printError(canvas, "Can't bake non-\"image sequence\" formats.");
@@ -1222,16 +1325,27 @@ static int dynamicPaint_createUVSurface(DynamicPaintSurface *surface)
if (!surface->data) return printError(canvas, "Not enough free memory.");
sData->samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
- tempPoints = (struct PaintTexturePoint *) MEM_callocN(w*h*sizeof(struct PaintTexturePoint), "PaintTexturePoint");
- if (tempPoints == NULL) return printError(canvas, "Not enough free memory.");
+ tempPoints = (struct PaintUVPoint *) MEM_callocN(w*h*sizeof(struct PaintUVPoint), "Temp PaintUVPoint");
+ if (!tempPoints) error=1;
+
+ final_index = (int *) MEM_callocN(w*h*sizeof(int), "Temp UV Final Indexes");
+ if (!final_index) error=1;
+
+ if (!error) {
+ tempWeights = (struct Vec3f *) MEM_mallocN(w*h*sData->samples*sizeof(struct Vec3f), "Temp bWeights");
+ if (!tempWeights) error=1;
+ }
/*
* Generate a temporary bounding box array for UV faces to optimize
* the pixel-inside-a-face search.
*/
- faceBB = (struct BB2d *) MEM_mallocN(numOfFaces*sizeof(struct BB2d), "MPCanvasFaceBB");
- if (faceBB == NULL) return printError(canvas, "Not enough free memory.");
+ if (!error) {
+ faceBB = (struct BB2d *) MEM_mallocN(numOfFaces*sizeof(struct BB2d), "MPCanvasFaceBB");
+ if (!faceBB) error=1;
+ }
+ if (!error)
for (yy=0; yy<numOfFaces; yy++) {
int numOfVert = (mface[yy].v4) ? 4 : 3;
int i;
@@ -1249,107 +1363,69 @@ static int dynamicPaint_createUVSurface(DynamicPaintSurface *surface)
}
/*
- * Allocate antialias sample data (without threads due to malloc)
- * (Non threadable?)
- */
- for (yy = 0; yy < h; yy++)
- {
- int xx;
- for (xx = 0; xx < w; xx++)
- {
- int index = xx+w*yy;
- PaintTexturePoint *tPoint = &tempPoints[index];
-
- /* Initialize barycentricWeights */
- tPoint->barycentricWeights = (struct Vec3f *) malloc( sData->samples * sizeof(struct Vec3f ));
- if (tPoint->barycentricWeights == NULL) return printError(canvas, "Not enough free memory.");
-
- }
- }
-
- /*
* Loop through every pixel and check
* if pixel is uv-mapped on a canvas face.
*/
- #pragma omp parallel for schedule(static)
- for (yy = 0; yy < h; yy++)
- {
- int xx;
- for (xx = 0; xx < w; xx++)
+ if (!error) {
+ #pragma omp parallel for schedule(static)
+ for (yy = 0; yy < h; yy++)
{
- int i, sample;
- int index = xx+w*yy;
- PaintTexturePoint *tPoint = (&tempPoints[index]);
+ int xx;
+ for (xx = 0; xx < w; xx++)
+ {
+ int i, sample;
+ int index = xx+w*yy;
+ PaintUVPoint *tPoint = (&tempPoints[index]);
- short isInside = 0; /* if point is inside a uv face */
+ short isInside = 0; /* if point is inside a uv face */
- float d1[2], d2[2], d3[2], point[5][2];
- float dot00,dot01,dot02,dot11,dot12, invDenom, u,v;
+ float d1[2], d2[2], d3[2], point[5][2];
+ float dot00,dot01,dot02,dot11,dot12, invDenom, u,v;
- /* Init per pixel settings */
- tPoint->face_index = -1;
- tPoint->pixel_index = index;
+ /* Init per pixel settings */
+ tPoint->face_index = -1;
+ tPoint->neighbour_pixel = -1;
+ tPoint->pixel_index = index;
- /* Actual pixel center, used when collision is found */
- point[0][0] = ((float)xx + 0.5f) / w;
- point[0][1] = ((float)yy + 0.5f) / h;
+ /* Actual pixel center, used when collision is found */
+ point[0][0] = ((float)xx + 0.5f) / w;
+ point[0][1] = ((float)yy + 0.5f) / h;
- /*
- * A pixel middle sample isn't enough to find very narrow polygons
- * So using 4 samples of each corner too
- */
- point[1][0] = ((float)xx) / w;
- point[1][1] = ((float)yy) / h;
+ /*
+ * A pixel middle sample isn't enough to find very narrow polygons
+ * So using 4 samples of each corner too
+ */
+ point[1][0] = ((float)xx) / w;
+ point[1][1] = ((float)yy) / h;
- point[2][0] = ((float)xx+1) / w;
- point[2][1] = ((float)yy) / h;
+ point[2][0] = ((float)xx+1) / w;
+ point[2][1] = ((float)yy) / h;
- point[3][0] = ((float)xx) / w;
- point[3][1] = ((float)yy+1) / h;
+ point[3][0] = ((float)xx) / w;
+ point[3][1] = ((float)yy+1) / h;
- point[4][0] = ((float)xx+1) / w;
- point[4][1] = ((float)yy+1) / h;
+ point[4][0] = ((float)xx+1) / w;
+ point[4][1] = ((float)yy+1) / h;
- /* Loop through samples, starting from middle point */
- for (sample=0; sample<5; sample++) {
-
- /* Loop through every face in the mesh */
- for (i=0; i<numOfFaces; i++) {
-
- /* Check uv bb */
- if (faceBB[i].min[0] > (point[sample][0])) continue;
- if (faceBB[i].min[1] > (point[sample][1])) continue;
- if (faceBB[i].max[0] < (point[sample][0])) continue;
- if (faceBB[i].max[1] < (point[sample][1])) continue;
-
- /* Calculate point inside a triangle check
- * for uv0,1,2 */
- VECSUB2D(d1, tface[i].uv[2], tface[i].uv[0]); // uv2 - uv0
- VECSUB2D(d2, tface[i].uv[1], tface[i].uv[0]); // uv1 - uv0
- VECSUB2D(d3, point[sample], tface[i].uv[0]); // point - uv0
-
- dot00 = d1[0]*d1[0] + d1[1]*d1[1];
- dot01 = d1[0]*d2[0] + d1[1]*d2[1];
- dot02 = d1[0]*d3[0] + d1[1]*d3[1];
- dot11 = d2[0]*d2[0] + d2[1]*d2[1];
- dot12 = d2[0]*d3[0] + d2[1]*d3[1];
-
- invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
- u = (dot11 * dot02 - dot01 * dot12) * invDenom;
- v = (dot00 * dot12 - dot01 * dot02) * invDenom;
-
- if ((u > 0) && (v > 0) && (u + v < 1)) {isInside=1;} /* is inside a triangle */
-
- /* If collision wasn't found but the face is a quad
- * do another check for the second half */
- if ((!isInside) && mface[i].v4)
- {
+ /* Loop through samples, starting from middle point */
+ for (sample=0; sample<5; sample++) {
+
+ /* Loop through every face in the mesh */
+ for (i=0; i<numOfFaces; i++) {
- /* change d2 to test the other half */
- VECSUB2D(d2, tface[i].uv[3], tface[i].uv[0]); // uv3 - uv0
+ /* Check uv bb */
+ if (faceBB[i].min[0] > (point[sample][0])) continue;
+ if (faceBB[i].min[1] > (point[sample][1])) continue;
+ if (faceBB[i].max[0] < (point[sample][0])) continue;
+ if (faceBB[i].max[1] < (point[sample][1])) continue;
+
+ /* Calculate point inside a triangle check
+ * for uv0,1,2 */
+ VECSUB2D(d1, tface[i].uv[2], tface[i].uv[0]); // uv2 - uv0
+ VECSUB2D(d2, tface[i].uv[1], tface[i].uv[0]); // uv1 - uv0
+ VECSUB2D(d3, point[sample], tface[i].uv[0]); // point - uv0
- /* test again */
dot00 = d1[0]*d1[0] + d1[1]*d1[1];
dot01 = d1[0]*d2[0] + d1[1]*d2[1];
dot02 = d1[0]*d3[0] + d1[1]*d3[1];
@@ -1360,231 +1436,304 @@ static int dynamicPaint_createUVSurface(DynamicPaintSurface *surface)
u = (dot11 * dot02 - dot01 * dot12) * invDenom;
v = (dot00 * dot12 - dot01 * dot02) * invDenom;
- if ((u > 0) && (v > 0) && (u + v < 1)) {isInside=2;} /* is inside the second half of the quad */
+ if ((u > 0) && (v > 0) && (u + v < 1)) {isInside=1;} /* is inside a triangle */
- }
+ /* If collision wasn't found but the face is a quad
+ * do another check for the second half */
+ if ((!isInside) && mface[i].v4)
+ {
- /*
- * If point was inside the face
- */
- if (isInside != 0) {
+ /* change d2 to test the other half */
+ VECSUB2D(d2, tface[i].uv[3], tface[i].uv[0]); // uv3 - uv0
- float uv1co[2], uv2co[2], uv3co[2], uv[2];
- int j;
+ /* test again */
+ dot00 = d1[0]*d1[0] + d1[1]*d1[1];
+ dot01 = d1[0]*d2[0] + d1[1]*d2[1];
+ dot02 = d1[0]*d3[0] + d1[1]*d3[1];
+ dot11 = d2[0]*d2[0] + d2[1]*d2[1];
+ dot12 = d2[0]*d3[0] + d2[1]*d3[1];
- /* Get triagnle uvs */
- if (isInside==1) {
- VECCOPY2D(uv1co, tface[i].uv[0]);
- VECCOPY2D(uv2co, tface[i].uv[1]);
- VECCOPY2D(uv3co, tface[i].uv[2]);
- }
- else {
- VECCOPY2D(uv1co, tface[i].uv[0]);
- VECCOPY2D(uv2co, tface[i].uv[2]);
- VECCOPY2D(uv3co, tface[i].uv[3]);
- }
+ invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
+ u = (dot11 * dot02 - dot01 * dot12) * invDenom;
+ v = (dot00 * dot12 - dot01 * dot02) * invDenom;
- /* Add b-weights per anti-aliasing sample */
- for (j=0; j<sData->samples; j++) {
- uv[0] = point[0][0] + jitter5sample[j*2] / w;
- uv[1] = point[0][1] + jitter5sample[j*2+1] / h;
+ if ((u > 0) && (v > 0) && (u + v < 1)) {isInside=2;} /* is inside the second half of the quad */
- barycentric_weights_v2(uv1co, uv2co, uv3co, uv, tPoint->barycentricWeights[j].v);
}
- /* Set surface point face values */
- tPoint->face_index = i; /* face index */
- tPoint->quad = (isInside == 2) ? 1 : 0; /* quad or tri part*/
+ /*
+ * If point was inside the face
+ */
+ if (isInside != 0) {
- /* save vertex indexes */
- tPoint->v1 = (isInside == 2) ? mface[i].v1 : mface[i].v1;
- tPoint->v2 = (isInside == 2) ? mface[i].v3 : mface[i].v2;
- tPoint->v3 = (isInside == 2) ? mface[i].v4 : mface[i].v3;
-
- sample = 5; /* make sure we exit sample loop as well */
- break;
- }
- }
- } /* sample loop */
- }
- }
+ float uv1co[2], uv2co[2], uv3co[2], uv[2];
+ int j;
+ /* Get triagnle uvs */
+ if (isInside==1) {
+ VECCOPY2D(uv1co, tface[i].uv[0]);
+ VECCOPY2D(uv2co, tface[i].uv[1]);
+ VECCOPY2D(uv3co, tface[i].uv[2]);
+ }
+ else {
+ VECCOPY2D(uv1co, tface[i].uv[0]);
+ VECCOPY2D(uv2co, tface[i].uv[2]);
+ VECCOPY2D(uv3co, tface[i].uv[3]);
+ }
+ /* Add b-weights per anti-aliasing sample */
+ for (j=0; j<sData->samples; j++) {
+ uv[0] = point[0][0] + jitter5sample[j*2] / w;
+ uv[1] = point[0][1] + jitter5sample[j*2+1] / h;
- /*
- * Now loop through every pixel that was left without index
- * and find if they have neighbouring pixels that have an index.
- * If so use that polygon as pixel surface.
- * (To avoid seams on uv island edges)
- */
- #pragma omp parallel for schedule(static)
- for (yy = 0; yy < h; yy++)
- {
- int xx;
- for (xx = 0; xx < w; xx++)
+ barycentric_weights_v2(uv1co, uv2co, uv3co, uv, tempWeights[index*sData->samples+j].v);
+ }
+
+ /* Set surface point face values */
+ tPoint->face_index = i; /* face index */
+ tPoint->quad = (isInside == 2) ? 1 : 0; /* quad or tri part*/
+
+ /* save vertex indexes */
+ tPoint->v1 = (isInside == 2) ? mface[i].v1 : mface[i].v1;
+ tPoint->v2 = (isInside == 2) ? mface[i].v3 : mface[i].v2;
+ tPoint->v3 = (isInside == 2) ? mface[i].v4 : mface[i].v3;
+
+ sample = 5; /* make sure we exit sample loop as well */
+ break;
+ }
+ }
+ } /* sample loop */
+ }
+ }
+
+ /*
+ * Now loop through every pixel that was left without index
+ * and find if they have neighbouring pixels that have an index.
+ * If so use that polygon as pixel surface.
+ * (To avoid seams on uv island edges)
+ */
+ #pragma omp parallel for schedule(static)
+ for (yy = 0; yy < h; yy++)
{
- int index = xx+w*yy;
- PaintTexturePoint *tPoint = (&tempPoints[index]);
-
- /* If point isnt't on canvas mesh */
- if (tPoint->face_index == -1) {
- int u_min, u_max, v_min, v_max;
- int u,v, ind;
- float point[2];
-
- /* get loop area */
- u_min = (xx > 0) ? -1 : 0;
- u_max = (xx < (w-1)) ? 1 : 0;
- v_min = (yy > 0) ? -1 : 0;
- v_max = (yy < (h-1)) ? 1 : 0;
-
- point[0] = ((float)xx + 0.5f) / w;
- point[1] = ((float)yy + 0.5f) / h;
-
- /* search through defined area for neighbour */
- for (u=u_min; u<=u_max; u++)
- for (v=v_min; v<=v_max; v++) {
- /* if not this pixel itself */
- if (u!=0 || v!=0) {
- ind = (xx+u)+w*(yy+v);
-
- /* if neighbour has index */
- if (tempPoints[ind].face_index != -1) {
-
- float uv1co[2], uv2co[2], uv3co[2], uv[2];
- int i = tempPoints[ind].face_index, j;
-
- /* Now calculate pixel data for this pixel as it was on polygon surface */
- if (!tempPoints[ind].quad) {
- VECCOPY2D(uv1co, tface[i].uv[0]);
- VECCOPY2D(uv2co, tface[i].uv[1]);
- VECCOPY2D(uv3co, tface[i].uv[2]);
- }
- else {
- VECCOPY2D(uv1co, tface[i].uv[0]);
- VECCOPY2D(uv2co, tface[i].uv[2]);
- VECCOPY2D(uv3co, tface[i].uv[3]);
- }
+ int xx;
+ for (xx = 0; xx < w; xx++)
+ {
+ int index = xx+w*yy;
+ PaintUVPoint *tPoint = (&tempPoints[index]);
+
+ /* If point isnt't on canvas mesh */
+ if (tPoint->face_index == -1) {
+ int u_min, u_max, v_min, v_max;
+ int u,v, ind;
+ float point[2];
+
+ /* get loop area */
+ u_min = (xx > 0) ? -1 : 0;
+ u_max = (xx < (w-1)) ? 1 : 0;
+ v_min = (yy > 0) ? -1 : 0;
+ v_max = (yy < (h-1)) ? 1 : 0;
+
+ point[0] = ((float)xx + 0.5f) / w;
+ point[1] = ((float)yy + 0.5f) / h;
+
+ /* search through defined area for neighbour */
+ for (u=u_min; u<=u_max; u++)
+ for (v=v_min; v<=v_max; v++) {
+ /* if not this pixel itself */
+ if (u!=0 || v!=0) {
+ ind = (xx+u)+w*(yy+v);
+
+ /* if neighbour has index */
+ if (tempPoints[ind].face_index != -1) {
+
+ float uv1co[2], uv2co[2], uv3co[2], uv[2];
+ int i = tempPoints[ind].face_index, j;
+
+ /* Now calculate pixel data for this pixel as it was on polygon surface */
+ if (!tempPoints[ind].quad) {
+ VECCOPY2D(uv1co, tface[i].uv[0]);
+ VECCOPY2D(uv2co, tface[i].uv[1]);
+ VECCOPY2D(uv3co, tface[i].uv[2]);
+ }
+ else {
+ VECCOPY2D(uv1co, tface[i].uv[0]);
+ VECCOPY2D(uv2co, tface[i].uv[2]);
+ VECCOPY2D(uv3co, tface[i].uv[3]);
+ }
- /* Add b-weights per anti-aliasing sample */
- for (j=0; j<sData->samples; j++) {
+ /* Add b-weights per anti-aliasing sample */
+ for (j=0; j<sData->samples; j++) {
- uv[0] = point[0] + jitter5sample[j*2] / w;
- uv[1] = point[1] + jitter5sample[j*2+1] / h;
- barycentric_weights_v2(uv1co, uv2co, uv3co, uv, tPoint->barycentricWeights[j].v);
- }
+ uv[0] = point[0] + jitter5sample[j*2] / w;
+ uv[1] = point[1] + jitter5sample[j*2+1] / h;
+ barycentric_weights_v2(uv1co, uv2co, uv3co, uv, tempWeights[index*sData->samples+j].v);
+ }
- /* Set values */
- tPoint->neighbour_pixel = ind; // face index
- tPoint->quad = tempPoints[ind].quad; // quad or tri
+ /* Set values */
+ tPoint->neighbour_pixel = ind; // face index
+ tPoint->quad = tempPoints[ind].quad; // quad or tri
- /* save vertex indexes */
- tPoint->v1 = (tPoint->quad) ? mface[i].v1 : mface[i].v1;
- tPoint->v2 = (tPoint->quad) ? mface[i].v3 : mface[i].v2;
- tPoint->v3 = (tPoint->quad) ? mface[i].v4 : mface[i].v3;
+ /* save vertex indexes */
+ tPoint->v1 = (tPoint->quad) ? mface[i].v1 : mface[i].v1;
+ tPoint->v2 = (tPoint->quad) ? mface[i].v3 : mface[i].v2;
+ tPoint->v3 = (tPoint->quad) ? mface[i].v4 : mface[i].v3;
- u = u_max + 1; /* make sure we exit outer loop as well */
- break;
- }
+ u = u_max + 1; /* make sure we exit outer loop as well */
+ break;
+ }
+ }
}
}
}
}
- }
- /*
- * When base loop is over convert found neighbour indexes to real ones
- * Also count the final number of active surface points
- */
- for (yy = 0; yy < h; yy++)
- {
- int xx;
- for (xx = 0; xx < w; xx++)
+ /*
+ * When base loop is over convert found neighbour indexes to real ones
+ * Also count the final number of active surface points
+ */
+ for (yy = 0; yy < h; yy++)
{
- int index = xx+w*yy;
- PaintTexturePoint *tPoint = (&tempPoints[index]);
+ int xx;
+ for (xx = 0; xx < w; xx++)
+ {
+ int index = xx+w*yy;
+ PaintUVPoint *tPoint = (&tempPoints[index]);
- if (tPoint->face_index == -1 && tPoint->neighbour_pixel != -1) tPoint->face_index = tempPoints[tPoint->neighbour_pixel].face_index;
- if (tPoint->face_index != -1) active_points++;
+ if (tPoint->face_index == -1 && tPoint->neighbour_pixel != -1) tPoint->face_index = tempPoints[tPoint->neighbour_pixel].face_index;
+ if (tPoint->face_index != -1) active_points++;
+ }
}
- }
-#if 0
- /* -----------------------------------------------------------------
- * For debug, output pixel statuses to the color map
- * -----------------------------------------------------------------*/
- #pragma omp parallel for schedule(static)
- for (yy = 0; yy < h; yy++)
- {
- int xx;
- for (xx = 0; xx < w; xx++)
- {
- int index = xx+w*yy;
- DynamicPaintSurfacePoint *cPoint = (&surface->point[index]);
- cPoint->alpha=1.0f;
- /* Every pixel that is assigned as "edge pixel" gets blue color */
- if (cPoint->neighbour_pixel != -1) cPoint->color[2] = 1.0f;
- /* and every pixel that finally got an polygon gets red color */
- if (cPoint->index != -1) cPoint->color[0] = 1.0f;
- /* green color shows pixel face index hash */
- if (cPoint->index != -1) cPoint->color[1] = (float)(cPoint->index % 255)/256.0f;
- }
- }
+ /* If any effect enabled, create surface effect / wet layer
+ * neighbour lists. Processes possibly moving data. */
+ if (surface->effect) {
-#endif
+ int i, cursor=0;
-#if 0 /* Currently disabled */
- /* If any effect enabled, create surface effect / wet layer
- * neighbour lists. Processes possibly moving data. */
- if (surface->effect) {
+ /* Create a temporary array of final indexes (before unassigned
+ * pixels have been dropped) */
+ for (i=0; i<w*h; i++) {
+ if (tempPoints[i].face_index != -1) {
+ final_index[i] = cursor;
+ cursor++;
+ }
+ }
- #pragma omp parallel for schedule(static)
- for (yy = 0; yy < h; yy++)
- {
- int xx;
- for (xx = 0; xx < w; xx++)
- {
- int i;
- DynamicPaintSurfacePoint *cPoint = (&surface->point[xx+w*yy]);
+ /* allocate memory */
+ sData->total_points = w*h;
+ dynamicPaint_initEffectData(surface);
+
+ if (sData->eff_data) {
+ PaintEffectData *ed = sData->eff_data;
+ unsigned int n_pos = 0;
+ //#pragma omp parallel for schedule(static)
+ for (yy = 0; yy < h; yy++)
+ {
+ int xx;
+ 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;
+ ed->numOf_n[final_index[index]] = 0;
+
+ for (i=0; i<8; i++) {
+
+ /* Try to find a neighbouring pixel in defined direction
+ * If not found, -1 is returned */
+ int n_target = dynamicPaint_findNeighbourPixel(tempPoints, dm, uvname, w, h, xx, yy, i);
+
+ if (n_target != -1) {
+ ed->n_target[n_pos] = final_index[n_target];
+ ed->numOf_n[final_index[index]]++;
+ n_pos++;
+ }
+ }
- /* If current point exists find all it's neighbouring pixels */
- if (cPoint->index != -1)
- for (i=0; i<8; i++) {
+ if (ed->numOf_n[final_index[index]] > ed->most_neighs)
+ ed->most_neighs = ed->numOf_n[final_index[index]];
- /* Try to find a neighbouring pixel in defined direction
- * If not found, -1 is returned */
- cPoint->neighbours[i] = dynamicPaint_findNeighbourPixel(canvas, xx, yy, i);
+ }
+ }
}
}
}
- }
-#endif
-
- MEM_freeN(faceBB);
- /* Create final surface data without inactive points */
- {
- int index, cursor = 0;
- PaintTexturePoint *tPoint = (struct PaintTexturePoint *) MEM_callocN(active_points*sizeof(struct PaintTexturePoint), "PaintTexturePoint");
+ /* Create final surface data without inactive points */
+ {
+ ImgSeqFormatData *f_data = MEM_callocN(sizeof(struct ImgSeqFormatData), "ImgSeqFormatData");
+ if (f_data) {
+ f_data->uv_p = MEM_callocN(active_points*sizeof(struct PaintUVPoint), "PaintUVPoint");
+ f_data->barycentricWeights = MEM_callocN(active_points*sData->samples*sizeof(struct Vec3f), "PaintUVPoint");
- sData->format_data = tPoint;
- if (sData->format_data == NULL) return printError(canvas, "Not enough free memory.");
- sData->total_points = active_points;
+ if (!f_data->uv_p || !f_data->barycentricWeights) error=1;
+ }
+ else error=1;
- for(index = 0; index < (w*h); index++) {
- if (tempPoints[index].face_index != -1) {
- memcpy(&tPoint[cursor], &tempPoints[index], sizeof(PaintTexturePoint));
- cursor++;
+ sData->total_points = active_points;
+
+ /* in case of allocation error, free everything */
+ if (error) {
+ if (f_data) {
+ if (f_data->uv_p) MEM_freeN(f_data->uv_p);
+ if (f_data->barycentricWeights) MEM_freeN(f_data->barycentricWeights);
+ MEM_freeN(f_data);
+ }
+ }
+ else {
+ int index, cursor = 0;
+ sData->total_points = active_points;
+ sData->format_data = f_data;
+
+ for(index = 0; index < (w*h); index++) {
+ if (tempPoints[index].face_index != -1) {
+ memcpy(&f_data->uv_p[cursor], &tempPoints[index], sizeof(PaintUVPoint));
+ memcpy(&f_data->barycentricWeights[cursor*sData->samples], &tempWeights[index*sData->samples], sizeof(Vec3f)*sData->samples);
+ cursor++;
+ }
+ }
}
}
- MEM_freeN(tempPoints);
}
+ if (error==1) printError(canvas, "Not enough free memory.");
+
+ if (faceBB) MEM_freeN(faceBB);
+ if (tempPoints) MEM_freeN(tempPoints);
+ if (tempWeights) MEM_freeN(tempWeights);
+ if (final_index) MEM_freeN(final_index);
/* Init surface type data */
- dynamicPaint_allocateSurfaceType(surface);
+ if (!error) {
+ int index;
+ dynamicPaint_allocateSurfaceType(surface);
- return 1;
+#if 0
+ /* -----------------------------------------------------------------
+ * For debug, output pixel statuses to the color map
+ * -----------------------------------------------------------------*/
+ #pragma omp parallel for schedule(static)
+ for (index = 0; index < sData->total_points; index++)
+ {
+ ImgSeqFormatData *f_data = (ImgSeqFormatData*)sData->format_data;
+ PaintUVPoint *uvPoint = &((PaintUVPoint*)f_data->uv_p)[index];
+ PaintPoint *pPoint = &((PaintPoint*)sData->type_data)[index];
+ pPoint->alpha=1.0f;
+
+ /* Every pixel that is assigned as "edge pixel" gets blue color */
+ if (uvPoint->neighbour_pixel != -1) pPoint->color[2] = 1.0f;
+ /* and every pixel that finally got an polygon gets red color */
+ if (uvPoint->face_index != -1) pPoint->color[0] = 1.0f;
+ /* green color shows pixel face index hash */
+ if (uvPoint->face_index != -1) pPoint->color[1] = (float)(uvPoint->face_index % 255)/256.0f;
+ }
+
+#endif
+ }
+
+ return (error == 0);
}
#define DPOUTPUT_PAINT 0
@@ -1600,7 +1749,7 @@ void dynamicPaint_outputImage(DynamicPaintSurface *surface, char* filename, shor
int index;
ImBuf* mhImgB = NULL;
PaintSurfaceData *sData = surface->data;
- PaintTexturePoint *tPoint = (PaintTexturePoint*)sData->format_data;
+ ImgSeqFormatData *f_data = (ImgSeqFormatData*)sData->format_data;
char output_file[250];
if (sData == NULL || sData->type_data == NULL) {printError(surface->canvas, "Image save failed: Invalid surface.");return;}
@@ -1620,7 +1769,7 @@ void dynamicPaint_outputImage(DynamicPaintSurface *surface, char* filename, shor
#pragma omp parallel for schedule(static)
for (index = 0; index < sData->total_points; index++)
{
- int pos=tPoint[index].pixel_index*4; /* image buffer position */
+ int pos=f_data->uv_p[index].pixel_index*4; /* image buffer position */
/* Set values of preferred type */
@@ -1635,20 +1784,12 @@ void dynamicPaint_outputImage(DynamicPaintSurface *surface, char* filename, shor
}
else if (type == DPOUTPUT_PAINT) {
PaintPoint *point = &((PaintPoint*)sData->type_data)[index];
- float invAlpha = 1.0f - point->e_alpha;
- /* If base layer already has a color, blend it */
- if (point->alpha) {
- mhImgB->rect_float[pos] = point->color[0] * invAlpha + point->e_color[0] * point->e_alpha;
- mhImgB->rect_float[pos+1] = point->color[1] * invAlpha + point->e_color[1] * point->e_alpha;
- mhImgB->rect_float[pos+2] = point->color[2] * invAlpha + point->e_color[2] * point->e_alpha;
- }
- else {
- /* Else use effect layer color */
- mhImgB->rect_float[pos] = point->e_color[0];
- mhImgB->rect_float[pos+1] = point->e_color[1];
- mhImgB->rect_float[pos+2] = point->e_color[2];
- }
+ mhImgB->rect_float[pos] = point->color[0];
+ mhImgB->rect_float[pos+1] = point->color[1];
+ mhImgB->rect_float[pos+2] = point->color[2];
+ /* mix wet layer */
+ if (point->e_alpha) mixColors(&mhImgB->rect_float[pos], point->alpha, point->e_color, point->e_alpha);
/* use highest alpha */
mhImgB->rect_float[pos+3] = (point->e_alpha > point->alpha) ? point->e_alpha : point->alpha;
@@ -1706,13 +1847,16 @@ void dynamicPaint_outputImage(DynamicPaintSurface *surface, char* filename, shor
* for material related objects in case texture is mapped to an object.
* (obj->imat isn't auto-updated)
*/
-static void dynamicPaint_updateMaterial(Material *mat, int frame)
+static void dynamicPaint_updateMaterial(Material *mat, Scene *scene)
{
MTex *mtex = NULL;
Tex *tex = NULL;
int tex_nr;
if (mat == NULL) return;
+ /* update material anims */
+ BKE_animsys_evaluate_animdata(&mat->id, mat->adt, BKE_curframe(scene), ADT_RECALC_ANIM);
+
/*
* Loop through every material texture and check
* if they are mapped by other object
@@ -1735,14 +1879,17 @@ static void dynamicPaint_updateMaterial(Material *mat, int frame)
}
}
+ /* update texture anims */
+ BKE_animsys_evaluate_animdata(&tex->id, tex->adt, BKE_curframe(scene), ADT_RECALC_ANIM);
+
/* update cache if voxel data */
if(tex->id.us && tex->type==TEX_VOXELDATA) {
- cache_voxeldata(tex, frame);
+ cache_voxeldata(tex, (int)scene->r.cfra);
}
/* update image sequences and movies */
if(tex->ima && ELEM(tex->ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
if(tex->iuser.flag & IMA_ANIM_ALWAYS)
- BKE_image_user_calc_frame(&tex->iuser, frame, 0);
+ BKE_image_user_calc_frame(&tex->iuser, (int)scene->r.cfra, 0);
}
}
}
@@ -1751,7 +1898,7 @@ static void dynamicPaint_updateMaterial(Material *mat, int frame)
/* Initialize materials for object:
* Calculates inverce matrices for linked objects, updates
* volume caches etc. */
-static void dynamicPaint_initObjectMaterials(Object *brushOb, Material *ui_mat, int frame)
+static void dynamicPaint_updateObjectMaterials(Object *brushOb, Material *ui_mat, Scene *scene)
{
/* Calculate inverse transformation matrix
* for this object */
@@ -1761,11 +1908,11 @@ static void dynamicPaint_initObjectMaterials(Object *brushOb, Material *ui_mat,
if ((ui_mat == NULL) && brushOb->mat && brushOb->totcol) {
int i, tot=(*give_totcolp(brushOb))+1;
for (i=1; i<tot; i++) {
- dynamicPaint_updateMaterial(give_current_material(brushOb,i), frame);
+ dynamicPaint_updateMaterial(give_current_material(brushOb,i), scene);
}
}
else {
- dynamicPaint_updateMaterial(ui_mat, frame);
+ dynamicPaint_updateMaterial(ui_mat, scene);
}
}
@@ -2295,33 +2442,17 @@ void dynamicPaint_mixPaintColors(DynamicPaintSurface *surface, int index, int pa
/* Add paint */
if (!(paintFlags & MOD_DPAINT_ERASE)) {
float wetness;
+ float temp_alpha = (*paintAlpha) * ((paintFlags & MOD_DPAINT_ABS_ALPHA) ? 1.0f : (*timescale));
- /* If point has previous paint */
- if (pPoint->e_alpha > 0)
- {
- /*
- * Mix colors by the factor, use timescale
- */
- float factor = (*paintAlpha) * (*timescale);
- float invFact = 1.0f - factor;
- pPoint->e_color[0] = pPoint->e_color[0]*invFact + paintColor[0]*factor;
- pPoint->e_color[1] = pPoint->e_color[1]*invFact + paintColor[1]*factor;
- pPoint->e_color[2] = pPoint->e_color[2]*invFact + paintColor[2]*factor;
- }
- else
- {
- /* else set first color value straight to paint color */
- pPoint->e_color[0] = paintColor[0];
- pPoint->e_color[1] = paintColor[1];
- pPoint->e_color[2] = paintColor[2];
- }
+ /* mix brush color with wet layer color */
+ if (temp_alpha) mixColors(pPoint->e_color, pPoint->e_alpha, paintColor, temp_alpha);
/* alpha */
if (paintFlags & MOD_DPAINT_ABS_ALPHA) {
if (pPoint->e_alpha < (*paintAlpha)) pPoint->e_alpha = (*paintAlpha);
}
else {
- pPoint->e_alpha += (*paintAlpha) * (*timescale);
+ pPoint->e_alpha += temp_alpha;
if (pPoint->e_alpha > 1.0f) pPoint->e_alpha = 1.0f;
}
@@ -2372,9 +2503,6 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface, PaintBakeData *b
if (!brush->dm) return 0;
- /* If using material color, we prepare required stuff on texture related objects first */
- if (brush->flags & MOD_DPAINT_USE_MATERIAL) dynamicPaint_initObjectMaterials(brushOb, brush->mat, surface->current_frame);
-
{
BVHTreeFromMesh treeData = {0};
int index;
@@ -2439,7 +2567,7 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface, PaintBakeData *b
}
/* Get current sample position in world coordinates */
- VECCOPY(ray_start, &bData->realCoord[(index*sData->samples+ss)*3]);
+ VECCOPY(ray_start, &bData->realCoord[(sData->total_points*ss+index)*3]);
VECCOPY(ray_dir, bData->bPoint[index].invNorm);
hit.index = -1;
@@ -2575,7 +2703,7 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface, PaintBakeData *b
sampleColor[2] = brush->b;
/* Get material+textures color on hit point if required */
- if (brush->flags & MOD_DPAINT_USE_MATERIAL) dynamicPaint_getMaterialColor(sampleColor, &sampleAlpha, brushOb, &bData->realCoord[(index*sData->samples+ss)*3], hitCoord, hitFace, hitQuad, brush->dm, brush->mat);
+ if (brush->flags & MOD_DPAINT_USE_MATERIAL) dynamicPaint_getMaterialColor(sampleColor, &sampleAlpha, brushOb, &bData->realCoord[(sData->total_points*ss+index)*3], hitCoord, hitFace, hitQuad, brush->dm, brush->mat);
/* Sample colorband if required */
if ((distRate >= 0.0f) && (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP) && do_colorband(brush->paint_ramp, distRate, bandres)) {
@@ -2742,7 +2870,7 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface, PaintBakeDa
int n, particles = 0;
float range = psys->part->size + smooth;
- particles = BLI_kdtree_range_search(tree, range, &bData->realCoord[(index*sData->samples)*3], NULL, &nearest);
+ particles = BLI_kdtree_range_search(tree, range, &bData->realCoord[index*3], NULL, &nearest);
for(n=0; n<particles; n++) {
/*
@@ -2788,7 +2916,7 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface, PaintBakeDa
radius = solidradius + smooth;
/* Find nearest particle and get distance to it */
- BLI_kdtree_find_nearest(tree, &bData->realCoord[(index*sData->samples)*3], NULL, &nearest);
+ BLI_kdtree_find_nearest(tree, &bData->realCoord[index*3], NULL, &nearest);
if (nearest.dist > radius) continue;
/* distances inside solid radius have maximum influence -> dist = 0 */
@@ -2851,6 +2979,358 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface, PaintBakeDa
/***************************** Dynamic Paint Step / Baking ******************************/
+/* paint effect default movement per frame in global units */
+#define EFF_MOVEMENT_PER_FRAME 0.05f
+
+/*
+* 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)
+{
+ double average_dist = 0.0f;
+ double average_force = 0.0f;
+ float shrink_speed=0.0f, spread_speed=0.0f;
+ float fastest_effect;
+ int steps;
+ PaintSurfaceData *sData = surface->data;
+ int index;
+
+ /* 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) */
+ *force = MEM_mallocN(sData->total_points*4*sizeof(float), "PaintEffectForces");
+
+ if (*force) {
+ #pragma omp parallel for schedule(static)
+ for (index = 0; index < sData->total_points; index++)
+ {
+ float forc[3] = {0};
+
+ /* apply force fields */
+ if (effectors) {
+ EffectedPoint epoint;
+ pd_point_from_loc(scene, &realCoords[index*3], vel, index, &epoint);
+ epoint.vel_to_sec = 1.0f;
+ pdDoEffectors(effectors, NULL, surface->effector_weights, &epoint, forc, NULL);
+ }
+
+ /* if global gravity is enabled, add it too */
+ if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY)
+ /* also divide by 10 to about match default grav
+ * with default force strength (1.0) */
+ madd_v3_v3fl(forc, scene->physics_settings.gravity,
+ surface->effector_weights->global_gravity*surface->effector_weights->weight[0] / 10.f);
+
+ /* force strength */
+ (*force)[index*4+3] = len_v3(forc);
+ /* normalize and copy */
+ if ((*force)[index*4+3]) mul_v3_fl(forc, 1.0f/(*force)[index*4+3]);
+ VECCOPY(&((*force)[index*4]), forc);
+ }
+ }
+ pdEndEffectors(&effectors);
+ }
+
+ /*
+ * Calculate current frame neighbouring pixel distances
+ * and average distance between those neighbours
+ */
+ #pragma omp parallel for schedule(static)
+ 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];
+
+ 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_force /= sData->total_points;
+ average_dist /= sData->eff_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 */
+
+ /* adjust number of required substep by fastest active effect */
+ if (surface->effect & MOD_DPAINT_EFFECT_DO_SPREAD)
+ spread_speed = surface->spread_speed;
+ if (surface->effect & MOD_DPAINT_EFFECT_DO_SHRINK)
+ shrink_speed = surface->shrink_speed;
+
+ fastest_effect = MAX3(spread_speed, shrink_speed, average_force);
+
+ steps = (int)ceil(EFF_MOVEMENT_PER_FRAME*fastest_effect/average_dist*timescale);
+ CLAMP(steps, 1, 8);
+
+ //printf("Average distance is %f, avg force %f, num of steps %i\n", average_dist, average_force, steps);
+
+ return steps;
+}
+
+/*
+* Processes active effect step.
+*/
+static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, EffBakeNPoint *eNeighs, float *force, PaintPoint *prevPoint, float timescale)
+{
+ PaintSurfaceData *sData = surface->data;
+ int index;
+
+ if (!sData->eff_data) return;
+ /*
+ * Spread Effect
+ */
+ if (surface->effect & MOD_DPAINT_EFFECT_DO_SPREAD) {
+ float eff_scale = EFF_MOVEMENT_PER_FRAME*surface->spread_speed*timescale;
+
+ /* Copy current surface to the previous points array to read unmodified values */
+ memcpy(prevPoint, sData->type_data, sData->total_points*sizeof(struct PaintPoint));
+
+ #pragma omp parallel for schedule(static)
+ for (index = 0; index < sData->total_points; index++)
+ {
+ int i;
+ int numOfNeighs = sData->eff_data->numOf_n[index];
+ float totalAlpha = 0.0f;
+ PaintPoint *pPoint = &((PaintPoint*)sData->type_data)[index];
+
+ /*
+ * Only reads values from the surface copy (prevPoint[]),
+ * so this one is thread safe
+ */
+
+ /* Loop through neighbouring points */
+ for (i=0; i<numOfNeighs; i++) {
+ int n_index = sData->eff_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;
+
+ totalAlpha += ePoint->e_alpha;
+
+ /* Check if neighbouring point has higher wetness,
+ * if so, add it's wetness to this point as well*/
+ if (ePoint->wetness <= pPoint->wetness) continue;
+ w_factor = ePoint->wetness/numOfNeighs * (ePoint->wetness - pPoint->wetness) * speed_scale;
+ if (w_factor <= 0.0f) continue;
+
+ if (ePoint->e_alpha > pPoint->e_alpha) {
+ alphaAdd = ePoint->e_alpha/numOfNeighs * (ePoint->wetness*ePoint->e_alpha - pPoint->wetness*pPoint->e_alpha) * speed_scale;
+ }
+
+ /* mix new color */
+ mixColors(pPoint->e_color, pPoint->e_alpha, ePoint->e_color, w_factor);
+
+ pPoint->e_alpha += alphaAdd;
+ pPoint->wetness += w_factor;
+
+ if (pPoint->e_alpha > 1.0f) pPoint->e_alpha = 1.0f;
+ }
+
+ /* For antialiasing sake, don't let alpha go much higher than average alpha of neighbours */
+ if (pPoint->e_alpha > (totalAlpha/numOfNeighs+0.25f)) {
+ pPoint->e_alpha = (totalAlpha/numOfNeighs+0.25f);
+ if (pPoint->e_alpha>1.0f) pPoint->e_alpha = 1.0f;
+ }
+ }
+ }
+
+ /*
+ * Shrink Effect
+ */
+ if (surface->effect & MOD_DPAINT_EFFECT_DO_SHRINK) {
+ float eff_scale = EFF_MOVEMENT_PER_FRAME*surface->shrink_speed*timescale;
+
+ /* Copy current surface to the previous points array to read unmodified values */
+ memcpy(prevPoint, sData->type_data, sData->total_points*sizeof(struct PaintPoint));
+
+ #pragma omp parallel for schedule(static)
+ for (index = 0; index < sData->total_points; index++)
+ {
+ int i;
+ int numOfNeighs = sData->eff_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]];
+ float a_factor, ea_factor, w_factor;
+
+ totalAlpha += ePoint->e_alpha;
+
+ /* Check if neighbouring point has lower alpha,
+ * if so, decrease this point's alpha as well*/
+ if (pPoint->alpha <= 0.0f && pPoint->e_alpha <= 0.0f && pPoint->wetness <= 0.0f) continue;
+
+ /* decrease factor for dry paint alpha */
+ a_factor = (1.0f - ePoint->alpha)/numOfNeighs * (pPoint->alpha - ePoint->alpha) * speed_scale;
+ if (a_factor < 0.0f) a_factor = 0.0f;
+ /* decrease factor for wet paint alpha */
+ ea_factor = (1.0f - ePoint->e_alpha)/8 * (pPoint->e_alpha - ePoint->e_alpha) * speed_scale;
+ if (ea_factor < 0.0f) ea_factor = 0.0f;
+ /* decrease factor for paint wetness */
+ w_factor = (1.0f - ePoint->wetness)/8 * (pPoint->wetness - ePoint->wetness) * speed_scale;
+ if (w_factor < 0.0f) w_factor = 0.0f;
+
+ if (a_factor) {
+ pPoint->alpha -= a_factor;
+ if (pPoint->alpha < 0.0f) pPoint->alpha = 0.0f;
+ pPoint->wetness -= a_factor;
+
+ }
+ else {
+ pPoint->e_alpha -= ea_factor;
+ if (pPoint->e_alpha < 0.0f) pPoint->e_alpha = 0.0f;
+ pPoint->wetness -= w_factor;
+ if (pPoint->wetness < 0.0f) pPoint->wetness = 0.0f;
+ }
+ }
+ }
+ }
+
+ /*
+ * Drip Effect
+ */
+ 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");
+
+ /* Copy current surface to the previous points array to read unmodified values */
+ memcpy(prevPoint, sData->type_data, sData->total_points*sizeof(struct PaintPoint));
+
+ 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;}
+ }
+
+ /* 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);
+
+ 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;}
+ }
+
+ /* 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];
+ }
+
+
+ /* 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]];
+
+ /* 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;
+
+ dir_factor = dir_dot * speed_scale * w_factor;
+ if (dir_factor > 1.0f) dir_factor = 1.0f;
+
+ /* mix new color */
+ mixColors(ePoint->e_color, ePoint->e_alpha, pPoint->e_color, 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 */
+ #pragma omp parallel for schedule(static)
+ for (index = 0; index < sData->total_points; index++)
+ {
+ PaintPoint *cPoint = &((PaintPoint*)sData->type_data)[index];
+
+ if (cPoint->e_alpha > 1.0f) cPoint->e_alpha=1.0f;
+ if (cPoint->wetness > 2.5f) cPoint->wetness=2.5f;
+
+ if (cPoint->e_alpha < 0.0f) cPoint->e_alpha=0.0f;
+ if (cPoint->wetness < 0.0f) cPoint->wetness=0.0f;
+ }
+ }
+}
#define VALUE_DISSOLVE(VALUE, SPEED, SCALE, LOG) (VALUE) = (LOG) ? (VALUE) * 1.0f - 1.0f/((SPEED)/(SCALE)) : (VALUE) - 1.0f/(SPEED)*(SCALE)
@@ -2860,11 +3340,10 @@ static int dynamicPaint_prepareSurfaceStep(DynamicPaintSurface *surface, PaintBa
MVert *mvert = dm->getVertArray(dm);
MFace *mface = dm->getFaceArray(dm);
- //MTFace *tface = DM_get_face_data_layer(dm, CD_MTFACE);
int index;
- FaceAdv *canvasInvNormals = NULL;
- Vec3f *canvasVerts = NULL;
+ FaceAdv *canvas_inv_normals = NULL;
+ Vec3f *canvas_verts = NULL;
int canvasNumOfVerts = dm->getNumVerts(dm);
int canvasNumOfFaces = dm->getNumFaces(dm);
@@ -2872,31 +3351,36 @@ static int dynamicPaint_prepareSurfaceStep(DynamicPaintSurface *surface, PaintBa
/*
* Make a transformed copy of canvas derived mesh vertices to avoid recalculation.
*/
- canvasVerts = (struct Vec3f *) MEM_mallocN(canvasNumOfVerts*sizeof(struct Vec3f), "Dynamic Paint transformed canvas verts");
- if (canvasVerts == NULL) return 0;
+ canvas_verts = (struct Vec3f *) MEM_mallocN(canvasNumOfVerts*sizeof(struct Vec3f), "Dynamic Paint transformed canvas verts");
+ if (!canvas_verts) return 0;
#pragma omp parallel for schedule(static)
for (index=0; index<canvasNumOfVerts; index++) {
/* Multiply coordinates by canvas transformation matrix */
- VECCOPY(canvasVerts[index].v, mvert[index].co);
- mul_m4_v3(ob->obmat, canvasVerts[index].v);
+ VECCOPY(canvas_verts[index].v, mvert[index].co);
+ mul_m4_v3(ob->obmat, canvas_verts[index].v);
}
/*
* Calculate temp per face normals using those transformed coordinates.
* (To not have to calculate same normal for millions of pixels)
*/
- canvasInvNormals = (struct FaceAdv *) MEM_callocN(canvasNumOfFaces*sizeof(struct FaceAdv), "Dynamic Paint canvas normals");
- if (canvasInvNormals == NULL) return 0;
+ canvas_inv_normals = (struct FaceAdv *) MEM_callocN(canvasNumOfFaces*sizeof(struct FaceAdv), "Dynamic Paint canvas normals");
+ if (!canvas_inv_normals) {
+ MEM_freeN(canvas_verts);
+ return 0;
+ }
#pragma omp parallel for schedule(static)
for (index=0; index<canvasNumOfFaces; index++) {
if (mface[index].flag & ME_SMOOTH) continue; /* Only calculate flat faces */
/* Transformed normal */
- normal_tri_v3( canvasInvNormals[index].no, canvasVerts[mface[index].v3].v, canvasVerts[mface[index].v2].v, canvasVerts[mface[index].v1].v);
- if (mface[index].v4) normal_tri_v3(canvasInvNormals[index].no_q, canvasVerts[mface[index].v4].v, canvasVerts[mface[index].v3].v, canvasVerts[mface[index].v1].v);
+ normal_tri_v3( canvas_inv_normals[index].no, canvas_verts[mface[index].v3].v,
+ canvas_verts[mface[index].v2].v, canvas_verts[mface[index].v1].v);
+ if (mface[index].v4) normal_tri_v3(canvas_inv_normals[index].no_q, canvas_verts[mface[index].v4].v,
+ canvas_verts[mface[index].v3].v, canvas_verts[mface[index].v1].v);
}
/*
@@ -2955,15 +3439,16 @@ static int dynamicPaint_prepareSurfaceStep(DynamicPaintSurface *surface, PaintBa
*/
if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
float n1[3], n2[3], n3[3];
- PaintTexturePoint *tPoint = &((PaintTexturePoint*)sData->format_data)[index];
+ ImgSeqFormatData *f_data = (ImgSeqFormatData*)sData->format_data;
+ PaintUVPoint *tPoint = &((PaintUVPoint*)f_data->uv_p)[index];
int ss;
/* per sample coordinates */
for (ss=0; ss<sData->samples; ss++) {
- interp_v3_v3v3v3( &bData->realCoord[(index*sData->samples+ss)*3],
- canvasVerts[tPoint->v1].v,
- canvasVerts[tPoint->v2].v,
- canvasVerts[tPoint->v3].v, tPoint->barycentricWeights[ss].v);
+ interp_v3_v3v3v3( &bData->realCoord[(sData->total_points*ss+index)*3],
+ canvas_verts[tPoint->v1].v,
+ canvas_verts[tPoint->v2].v,
+ canvas_verts[tPoint->v3].v, f_data->barycentricWeights[index*sData->samples+ss].v);
}
/* Calculate current pixel surface normal */
@@ -2973,21 +3458,21 @@ static int dynamicPaint_prepareSurfaceStep(DynamicPaintSurface *surface, PaintBa
normal_short_to_float_v3(n3, mvert[tPoint->v3].no);
interp_v3_v3v3v3( bData->bPoint[index].invNorm,
- n1, n2, n3, tPoint->barycentricWeights[0].v);
+ n1, n2, n3, f_data->barycentricWeights[index*sData->samples].v);
mul_mat3_m4_v3(ob->obmat, bData->bPoint[index].invNorm);
normalize_v3(bData->bPoint[index].invNorm);
negate_v3(bData->bPoint[index].invNorm);
}
else {
- if (tPoint->quad) {VECCOPY(bData->bPoint[index].invNorm, canvasInvNormals[tPoint->face_index].no_q);}
- else {VECCOPY(bData->bPoint[index].invNorm, canvasInvNormals[tPoint->face_index].no);}
+ if (tPoint->quad) {VECCOPY(bData->bPoint[index].invNorm, canvas_inv_normals[tPoint->face_index].no_q);}
+ else {VECCOPY(bData->bPoint[index].invNorm, canvas_inv_normals[tPoint->face_index].no);}
}
}
else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
/* In case of verted data */
/* location, currently vertex format can have only one sample */
- VECCOPY(&bData->realCoord[index*3], canvasVerts[index].v);
+ VECCOPY(&bData->realCoord[index*3], canvas_verts[index].v);
/* normal */
normal_short_to_float_v3(bData->bPoint[index].invNorm, mvert[index].no);
@@ -3014,18 +3499,28 @@ static int dynamicPaint_prepareSurfaceStep(DynamicPaintSurface *surface, PaintBa
*/
}
- MEM_freeN(canvasVerts);
- MEM_freeN(canvasInvNormals);
+ MEM_freeN(canvas_verts);
+ MEM_freeN(canvas_inv_normals);
return 1;
}
static void scene_updateObject(Scene *scene, Object *ob, float frame) {
int oflags;
+
+ /* if object has parent, update it too */
+ if (ob->parent) scene_updateObject(scene, ob->parent, frame);
+ if (ob->track) scene_updateObject(scene, ob->track, frame);
+
+ /* for curve */
+ if(ob->type==OB_CURVE) {
+ Curve *cu= ob->data;
+ BKE_animsys_evaluate_animdata(&cu->id, cu->adt, frame, ADT_RECALC_ANIM);
+ }
+
/* backup object flags */
oflags = ob->recalc;
-
ob->recalc |= OB_RECALC_ALL;
ob->recalc |= OB_RECALC_DATA;
BKE_animsys_evaluate_animdata(&ob->id, ob->adt, frame, ADT_RECALC_ANIM);
@@ -3049,6 +3544,7 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
PaintSurfaceData *sData = surface->data;
DynamicPaintCanvasSettings *canvas = surface->canvas;
PaintBakeData bData;
+ int ret = 1;
if (!sData || sData->total_points < 1) return 0;
@@ -3058,12 +3554,14 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
bData.realCoord = (float *) MEM_mallocN(sData->total_points*3*sData->samples*sizeof(float), "Dynamic Paint step coords");
if (bData.realCoord == NULL) return printError(canvas, "Not enough free memory.");
- if (!dynamicPaint_prepareSurfaceStep(surface, &bData, ob, canvas->dm, timescale))
- return printError(canvas, "Not enough free memory.");
-
+ if (!dynamicPaint_prepareSurfaceStep(surface, &bData, ob, canvas->dm, timescale)) {
+ ret = 0;
+ printError(canvas, "Not enough free memory.");
+ }
/*
* Loop through surface's target paint objects and do painting
*/
+ else
{
Base *base = NULL;
GroupObject *go = NULL;
@@ -3124,6 +3622,9 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
scene_updateObject(scene, brushObj, BKE_curframe(scene));
}
+ /* If using material color, update anim data to current (sub)frame */
+ if (brush->flags & MOD_DPAINT_USE_MATERIAL)
+ dynamicPaint_updateObjectMaterials(brushObj, brush->mat, scene);
/* Check if painter has a particle system selected
* -> if so, do particle painting */
@@ -3131,16 +3632,14 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
{
if (brush && brush->psys && brush->psys->part && brush->psys->part->type==PART_EMITTER)
if (psys_check_enabled(brushObj, brush->psys)) {
- /*
- * Paint a particle system
- */
+
+ /* Paint a particle system */
+ BKE_animsys_evaluate_animdata(&brush->psys->part->id, brush->psys->part->adt, BKE_curframe(scene), ADT_RECALC_ANIM);
dynamicPaint_paintParticles(surface, &bData, brush->psys, brush, ob, timescale);
}
}
else {
- /*
- * Paint a object mesh
- */
+ /* Paint a mesh */
dynamicPaint_paintMesh(surface, &bData, brush, ob, brushObj, timescale);
}
@@ -3149,6 +3648,7 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
scene->r.cfra = scene_frame;
scene->r.subframe = scene_subframe;
scene_updateObject(scene, brushObj, BKE_curframe(scene));
+ dynamicPaint_updateObjectMaterials(brushObj, brush->mat, scene);
}
} /* end of collision check (Is valid paint modifier) */
}
@@ -3156,9 +3656,51 @@ 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)
+ {
+ int steps = 1, s;
+ PaintPoint *prevPoint;
+ EffBakeNPoint *eNeighs;
+ float *force = NULL;
+
+ /* 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");
+
+ /* 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);
+
+ return printError(canvas, "Not enough free memory.");
+ }
+
+ /* Prepare effects and get number of required steps */
+ steps = dynamicPaint_prepareEffectStep(surface, scene, ob, eNeighs, &force, bData.realCoord, timescale);
+
+ /*
+ * Do Effects steps
+ */
+ for (s = 0; s < steps; s++)
+ {
+ dynamicPaint_doEffectStep(surface, eNeighs, force, prevPoint, timescale/(float)steps);
+ }
+
+ /* Free temporary effect data */
+ if (eNeighs) MEM_freeN(eNeighs);
+ if (prevPoint) MEM_freeN(prevPoint);
+ if (force) MEM_freeN(force);
+ }
+
MEM_freeN(bData.realCoord);
- return 1;
+ return ret;
}
/*
@@ -3212,13 +3754,12 @@ static int dynamicPaint_bakeImageSequence(bContext *C, DynamicPaintSurface *surf
/* Init surface */
if (!dynamicPaint_createUVSurface(surface)) return 0;
-
/*
* Loop through selected frames
*/
for (frame=surface->start_frame; frame<=surface->end_frame; frame++)
{
- float timescale = 1.0f / (surface->substeps+1);
+ float timescale = 1.0f;
int st;
float progress = (frame - surface->start_frame) / (float)frames * 100;
surface->current_frame = frame;
@@ -3237,6 +3778,7 @@ static int dynamicPaint_bakeImageSequence(bContext *C, DynamicPaintSurface *surf
*/
if (frame != surface->start_frame) {
/* change to next frame */
+ timescale /= (surface->substeps+1);
scene->r.cfra = (int)frame;
scene->r.subframe = 0.0f;
ED_update_for_newframe(CTX_data_main(C), scene, win->screen, 1);
@@ -3277,11 +3819,14 @@ static int dynamicPaint_bakeImageSequence(bContext *C, DynamicPaintSurface *surf
/* color map */
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- 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_PAINT);
-
- sprintf(filename, "%s%s%s%s%i", surface->image_output_path, dir_slash, surface->output_name2, pad, (int)frame);
- dynamicPaint_outputImage(surface, filename, format, DPOUTPUT_WET);
+ if (surface->flags & MOD_DPAINT_OUT1) {
+ 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_PAINT);
+ }
+ if (surface->flags & MOD_DPAINT_OUT2) {
+ sprintf(filename, "%s%s%s%s%i", surface->image_output_path, dir_slash, surface->output_name2, pad, (int)frame);
+ dynamicPaint_outputImage(surface, filename, format, DPOUTPUT_WET);
+ }
}
/* displacement map */
@@ -3329,10 +3874,10 @@ static int dynamicPaint_initBake(bContext *C, wmOperator *op)
/* Bake Dynamic Paint */
status = dynamicPaint_bakeImageSequence(C, surface, cObject);
- /* Clean bake flag */
+ /* Clear bake */
pmd->canvas->flags &= ~MOD_DPAINT_BAKING;
- /* Restore cursor back to normal */
WM_cursor_restore(CTX_wm_window(C));
+ dynamicPaint_freeSurfaceData(surface);
/* Bake was successful:
* Report for ended bake and how long it took */
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 0b3e2dc2577..19f520033ad 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -4042,6 +4042,9 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
surface->canvas = pmd->canvas;
surface->data = NULL;
direct_link_pointcache_list(fd, &(surface->ptcaches), &(surface->pointcache), 1);
+
+ if(!(surface->effector_weights = newdataadr(fd, surface->effector_weights)))
+ surface->effector_weights = BKE_add_effector_weights(NULL);
}
}
}
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 0a22a66fe61..97e5c300eab 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -1263,9 +1263,12 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
/* write surfaces */
for (surface=pmd->canvas->surfaces.first; surface; surface=surface->next)
writestruct(wd, DATA, "DynamicPaintSurface", 1, surface);
- /* write caches */
- for (surface=pmd->canvas->surfaces.first; surface; surface=surface->next)
+ /* write caches and effector weights */
+ for (surface=pmd->canvas->surfaces.first; surface; surface=surface->next) {
write_pointcaches(wd, &(surface->ptcaches));
+
+ writestruct(wd, DATA, "EffectorWeights", 1, surface->effector_weights);
+ }
}
else if(pmd->type & MOD_DYNAMICPAINT_TYPE_BRUSH && pmd->brush)
{
diff --git a/source/blender/makesdna/DNA_dynamicpaint_types.h b/source/blender/makesdna/DNA_dynamicpaint_types.h
index faead0a264f..3ec8c9d5fd6 100644
--- a/source/blender/makesdna/DNA_dynamicpaint_types.h
+++ b/source/blender/makesdna/DNA_dynamicpaint_types.h
@@ -39,6 +39,10 @@ struct PaintSurfaceData;
#define MOD_DPAINT_PREVIEW (1<<6) /* preview this surface on viewport*/
+/* image sequence output */
+#define MOD_DPAINT_OUT1 (1<<10) /* output primary surface */
+#define MOD_DPAINT_OUT2 (1<<11) /* output secondary surface */
+
/* canvas flags */
#define MOD_DPAINT_PREVIEW_READY (1<<0) /* if viewport preview is ready */
#define MOD_DPAINT_BAKING (1<<1) /* baking an image sequence */
@@ -63,6 +67,7 @@ typedef struct DynamicPaintSurface {
struct PaintSurfaceData *data;
struct Group *brush_group;
+ struct EffectorWeights *effector_weights;
/* cache */
struct PointCache *pointcache;
@@ -76,7 +81,6 @@ typedef struct DynamicPaintSurface {
short effect_ui; /* just ui selection box */
short pad;
int flags, effect;
- float intitial_color[4];
int image_resolution, substeps;
int start_frame, end_frame;
@@ -84,7 +88,7 @@ typedef struct DynamicPaintSurface {
int dry_speed, diss_speed;
float disp_depth;
- float spread_speed, drip_speed, shrink_speed;
+ float spread_speed, shrink_speed, pad_f;
char uvlayer_name[32];
char image_output_path[240];
diff --git a/source/blender/makesrna/intern/rna_dynamicpaint.c b/source/blender/makesrna/intern/rna_dynamicpaint.c
index 405f083d8bf..0b0450d62a8 100644
--- a/source/blender/makesrna/intern/rna_dynamicpaint.c
+++ b/source/blender/makesrna/intern/rna_dynamicpaint.c
@@ -353,12 +353,6 @@ static void rna_def_canvas_surface(BlenderRNA *brna)
/*
* Paint, wet and disp
*/
- prop= RNA_def_property(srna, "initial_color", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_float_sdna(prop, NULL, "intitial_color");
- RNA_def_property_array(prop, 4);
- RNA_def_property_ui_text(prop, "Initial Color", "Initial surface color");
- RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_DynamicPaintSurface_reset");
prop= RNA_def_property(srna, "use_dissolve", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DPAINT_DISSOLVE);
@@ -441,30 +435,29 @@ static void rna_def_canvas_surface(BlenderRNA *brna)
prop= RNA_def_property(srna, "spread_speed", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "spread_speed");
- RNA_def_property_range(prop, 0.1, 5.0);
- RNA_def_property_ui_range(prop, 0.1, 5.0, 1, 2);
+ RNA_def_property_range(prop, 0.01, 5.0);
+ RNA_def_property_ui_range(prop, 0.001, 20.0, 1, 2);
RNA_def_property_ui_text(prop, "Spread Speed", "How fast spread effect moves on the canvas surface.");
prop= RNA_def_property(srna, "use_drip", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "effect", MOD_DPAINT_EFFECT_DO_DRIP);
RNA_def_property_ui_text(prop, "Use Drip", "Processes drip effect. Drips wet paint to gravity direction.");
- prop= RNA_def_property(srna, "drip_speed", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "drip_speed");
- RNA_def_property_range(prop, 0.1, 5.0);
- RNA_def_property_ui_range(prop, 0.1, 5.0, 1, 2);
- RNA_def_property_ui_text(prop, "Drip Speed", "How fast drip effect moves on the canvas surface.");
-
prop= RNA_def_property(srna, "use_shrink", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "effect", MOD_DPAINT_EFFECT_DO_SHRINK);
RNA_def_property_ui_text(prop, "Use Shrink", "Processes shrink effect. Shrinks paint areas.");
prop= RNA_def_property(srna, "shrink_speed", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "shrink_speed");
- RNA_def_property_range(prop, 0.1, 5.0);
- RNA_def_property_ui_range(prop, 0.1, 5.0, 1, 2);
+ RNA_def_property_range(prop, 0.01, 5.0);
+ RNA_def_property_ui_range(prop, 0.01, 20.0, 1, 2);
RNA_def_property_ui_text(prop, "Shrink Speed", "How fast shrink effect moves on the canvas surface.");
+ prop= RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "EffectorWeights");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Effector Weights", "");
+
/*
* Output settings
*/
@@ -482,11 +475,18 @@ static void rna_def_canvas_surface(BlenderRNA *brna)
RNA_def_property_string_sdna(prop, NULL, "output_name");
RNA_def_property_ui_text(prop, "Output name", "");
+ prop= RNA_def_property(srna, "do_output1", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DPAINT_OUT1);
+ RNA_def_property_ui_text(prop, "Save layer", "");
+
/* output for secondary sufrace data */
prop= RNA_def_property(srna, "output_name2", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "output_name2");
RNA_def_property_ui_text(prop, "Output name", "");
- //RNA_def_property_string_funcs(prop, NULL, NULL, "rna_DynamicPaint_uvlayer_set");
+
+ prop= RNA_def_property(srna, "do_output2", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DPAINT_OUT2);
+ RNA_def_property_ui_text(prop, "Save layer", "");
prop= RNA_def_property(srna, "displacement", PROP_FLOAT, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index 5d3c29b736b..11c350e3011 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -643,6 +643,22 @@ static char *rna_EffectorWeight_path(PointerRNA *ptr)
if (smd->domain->effector_weights == ew)
return BLI_sprintfN("modifiers[\"%s\"].settings.effector_weights", md->name);
}
+
+ /* check dynamic paint modifier */
+ md = (ModifierData *)modifiers_findByType(ob, eModifierType_DynamicPaint);
+ if (md) {
+ DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
+
+ if (pmd->canvas) {
+ DynamicPaintSurface *surface = pmd->canvas->surfaces.first;
+
+ for(; surface; surface=surface->next) {
+ if (surface->effector_weights == ew)
+ return BLI_sprintfN("modifiers[\"%s\"].canvas_settings.canvas_surfaces[\"%s\"].effector_weights",
+ md->name, surface->name);
+ }
+ }
+ }
}
return NULL;
}