diff options
author | Miika Hamalainen <blender@miikah.org> | 2011-07-22 22:37:30 +0400 |
---|---|---|
committer | Miika Hamalainen <blender@miikah.org> | 2011-07-22 22:37:30 +0400 |
commit | cbe1613c0123d7705b9bba3806c03fe09151e729 (patch) | |
tree | 5d9b0f775a8c646959bc0b76545d02719700866a | |
parent | 4b80e1aba2e6f92b08ceddca2cab7d108ef8fac0 (diff) |
Dynamic Paint:
* Surface bake data is no longer recalculated every frame, but only when surface mesh has moved/transformed. Results in multiple times better performance on high resolution surfaces when using sub-steps or surface is still.
* Heavily optimized particle brushes when random particle size enabled. Up to 10x speedup with large radius particles.
* Added an additional "grid" space partitioning structure for surfaces.
* Added bounding box checks for brushes.
* Smaller overall optimization.
* Further OpenMP parallelization.
* Added physics tab link to modifier panel.
* Fix: "Point Density" texture cache wasn't properly updated. Brushes can now use Point Density textures as well.
* Fix: Paint dissolve resulted in black color.
* Fix: KD-tree checkups weren't completely thread safe. Fixes possible crash with OpenMP enabled particle brushes.
* Fix: When brush was set to use a specific material, it was saved incorrectly and resulted in potential crashes on next load.
-rw-r--r-- | source/blender/blenkernel/BKE_dynamicpaint.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/dynamicpaint.c | 1612 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_kdtree.h | 8 | ||||
-rw-r--r-- | source/blender/blenlib/intern/BLI_kdtree.c | 94 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 3 | ||||
-rw-r--r-- | source/blender/blenloader/intern/writefile.c | 1 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_templates.c | 2 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_dynamicpaint_types.h | 8 | ||||
-rw-r--r-- | source/blender/modifiers/intern/MOD_dynamicpaint.c | 3 | ||||
-rw-r--r-- | source/blender/render/intern/include/pointdensity.h | 1 | ||||
-rw-r--r-- | source/blender/render/intern/source/pointdensity.c | 2 | ||||
-rw-r--r-- | source/blenderplayer/bad_level_call_stubs/stubs.c | 1 |
12 files changed, 1110 insertions, 627 deletions
diff --git a/source/blender/blenkernel/BKE_dynamicpaint.h b/source/blender/blenkernel/BKE_dynamicpaint.h index e8e932da97e..c49a13f7d0e 100644 --- a/source/blender/blenkernel/BKE_dynamicpaint.h +++ b/source/blender/blenkernel/BKE_dynamicpaint.h @@ -17,6 +17,7 @@ #include "DNA_dynamicpaint_types.h" struct PaintEffectData; +struct PaintBakeData; /* Actual surface point */ typedef struct PaintSurfaceData { @@ -27,6 +28,7 @@ typedef struct PaintSurfaceData { /* point neighbor data */ struct PaintAdjData *adj_data; + struct PaintBakeData *bData; unsigned int total_points; } PaintSurfaceData; diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 8a616ff47e0..f2b4cc7d351 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -81,11 +81,16 @@ /* to read object material color */ #include "DNA_texture_types.h" +#include "../render/intern/include/pointdensity.h" #include "../render/intern/include/render_types.h" #include "../render/intern/include/voxeldata.h" #include "DNA_material_types.h" #include "RE_render_ext.h" +#ifdef _OPENMP +#include <omp.h> +#endif + #define DPOUTPUT_JPEG 0 #define DPOUTPUT_PNG 1 #define DPOUTPUT_OPENEXR 2 @@ -113,31 +118,54 @@ static int dynamicPaint_calculateFrame(DynamicPaintSurface *surface, Scene *scen /***************************** Internal Structs ***************************/ -typedef struct FaceAdv { - float no[3]; - float no_q[3]; -} FaceAdv; - -typedef struct BB2d { +typedef struct Bounds2D { float min[2], max[2]; -} BB2d; +} Bounds2D; + +typedef struct Bounds3D { + float min[3], max[3]; +} Bounds3D; + +typedef struct VolumeGrid { + int x,y,z; + Bounds3D grid_bounds; + + Bounds3D *bounds; /* (x*y*z) precalculated grid cell bounds */ + unsigned int *s_pos; /* (x*y*z) search indexses */ + unsigned int *s_num; /* (x*y*z) number of points */ + unsigned int *t_index; /* actual point index, + access: (s_pos+s_num) */ +} VolumeGrid; typedef struct Vec3f { float v[3]; } Vec3f; +typedef struct BakeNeighPoint { + float dir[3]; /* vector pointing towards this neighbour */ + float dist; /* distance to */ +} BakeNeighPoint; + /* Surface data used while processing a frame */ -typedef struct PaintBakePoint { - float invNorm[3]; /* current pixel world-space inverted normal. depends on face shading mode */ +typedef struct PaintBakeNormal { + float invNorm[3]; /* current pixel world-space inverted normal */ float normal_scale; /* normal directional scale for displace mapping */ -} PaintBakePoint; +} PaintBakeNormal; +/* Temp surface data used to process a frame */ typedef struct PaintBakeData { - PaintBakePoint *bPoint; - unsigned int *s_index; /* index to start reading point sample realcoords */ + PaintBakeNormal *bNormal; + unsigned int *s_pos; /* index to start reading point sample realCoord */ unsigned int *s_num; /* num of samples for each point */ - float *realCoord; /* current pixel center world-space coordinates * numOfSamples - * ordered as (s_index+sample_num)*3*/ + Vec3f *realCoord; /* current pixel center world-space coordinates * numOfSamples + * ordered as (s_pos+sample_num)*/ + + BakeNeighPoint *bNeighs; /* current frame neighbour distances, if required */ + VolumeGrid *grid; /* space partitioning grid to optimize brush checks */ + + MVert *prev_verts; /* copy of previous frame vertices. used observe surface movement */ + float prev_obmat[4][4]; /* previous frame object matrix */ + } PaintBakeData; /* UV Image sequence format point */ @@ -161,11 +189,6 @@ typedef struct EffVelPoint { float previous_vel[3]; } EffVelPoint; -typedef struct BakeNeighPoint { - float dir[3]; /* vector pointing towards this neighbour */ - float dist; /* distance to */ -} BakeNeighPoint; - /* adjacency data flags */ #define ADJ_ON_MESH_EDGE (1<<0) @@ -316,11 +339,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 int surface_totalSamples(DynamicPaintSurface *surface) +{ + if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ && + surface->flags & MOD_DPAINT_ANTIALIAS) + return (surface->data->total_points*5); + if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX && + surface->flags & MOD_DPAINT_ANTIALIAS && surface->data->adj_data) + return (surface->data->total_points+surface->data->adj_data->total_targets); + + return surface->data->total_points; +} + +/* assumes source alpha > 0.0f or results NaN colors */ 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; @@ -334,6 +370,234 @@ static void mixColors(float *t_color, float t_alpha, float *s_color, float s_alp t_color[2] = t_color[2]*invFact + s_color[2]*factor; } +static int boundsIntersect(Bounds3D *b1, Bounds3D *b2) +{ + int i=2; + for (; i>=0; i-=1) + if (!(b1->min[i] <= b2->max[i] && b1->max[i] >= b2->min[i])) return 0; + return 1; +} + +static int boundsIntersectDist(Bounds3D *b1, Bounds3D *b2, float dist) +{ + int i=2; + for (; i>=0; i-=1) + if (!(b1->min[i] <= (b2->max[i]+dist) && b1->max[i] >= (b2->min[i]-dist))) return 0; + return 1; +} + +static int boundIntersectPoint(Bounds3D *b, float point[3], float radius) +{ + int i=2; + for (; i>=0; i-=1) + if (!(b->min[i] <= (point[i]+radius) && b->max[i] >= (point[i]-radius))) return 0; + return 1; +} + +static void boundInsert(Bounds3D *b, float point[3]) +{ + int i=2; + for (; i>=0; i-=1) { + if (point[i] < b->min[i]) b->min[i]=point[i]; + if (point[i] > b->max[i]) b->max[i]=point[i]; + } +} + +static void freeGrid(PaintSurfaceData *data) +{ + PaintBakeData *bData = data->bData; + VolumeGrid *grid = bData->grid; + + if (grid->bounds) MEM_freeN(grid->bounds); + if (grid->s_pos) MEM_freeN(grid->s_pos); + if (grid->s_num) MEM_freeN(grid->s_num); + if (grid->t_index) MEM_freeN(grid->t_index); + + MEM_freeN(bData->grid); + bData->grid = NULL; +} + +static void surfaceGenerateGrid(struct DynamicPaintSurface *surface) +{ + PaintSurfaceData *sData = surface->data; + PaintBakeData *bData = sData->bData; + Bounds3D *grid_bounds; + VolumeGrid *grid; + int grid_cells, axis = 3; + int *temp_t_index = NULL; + int *temp_s_num = NULL; + +#ifdef _OPENMP + int num_of_threads = omp_get_max_threads(); +#else + int num_of_threads = 1; +#endif + + if (bData->grid) + freeGrid(sData); + + /* allocate separate bounds for each thread */ + grid_bounds = MEM_callocN(sizeof(Bounds3D)*num_of_threads, "Grid Bounds"); + + bData->grid = MEM_callocN(sizeof(VolumeGrid), "Surface Grid"); + grid = bData->grid; + + if (grid && grid_bounds) { + int index, error = 0; + float dim_factor, volume, dim[3]; + float tx,ty,tz; + + /* initial values for each thread */ + for (index = 0; index<num_of_threads; index++) { + VECCOPY(grid_bounds[index].min, bData->realCoord[bData->s_pos[0]].v); + VECCOPY(grid_bounds[index].max, bData->realCoord[bData->s_pos[0]].v); + } + VECCOPY(grid->grid_bounds.min, bData->realCoord[bData->s_pos[0]].v); + VECCOPY(grid->grid_bounds.max, bData->realCoord[bData->s_pos[0]].v); + + /* calculate canvas dimensions */ + #pragma omp parallel for schedule(static) + for (index = 1; index < sData->total_points; index++) { +#ifdef _OPENMP + int id = omp_get_thread_num(); + boundInsert(&grid_bounds[id], (bData->realCoord[bData->s_pos[index]].v)); +#else + boundInsert(&grid_bounds[0], (bData->realCoord[bData->s_pos[index]].v)); +#endif + } + + /* get final dimensions */ + for (index = 0; index<num_of_threads; index++) { + boundInsert(&grid->grid_bounds, grid_bounds[index].min); + boundInsert(&grid->grid_bounds, grid_bounds[index].max); + } + + dim[0] = grid->grid_bounds.max[0]-grid->grid_bounds.min[0]; + dim[1] = grid->grid_bounds.max[1]-grid->grid_bounds.min[1]; + dim[2] = grid->grid_bounds.max[2]-grid->grid_bounds.min[2]; + + tx = dim[0]; + ty = dim[1]; + tz = dim[2]; + + /* deactivate zero axises */ + if (!tx) {tx=1.0f; axis-=1;} + if (!ty) {ty=1.0f; axis-=1;} + if (!tz) {tz=1.0f; axis-=1;} + + if (axis == 0) + return; + + /* now with values scaled >= 1.0f, calculate scaled grid volume */ + volume = tx*ty*tz; + + /* determine final grid size by trying to fit average 10.000 points per grid cell */ + dim_factor = pow(volume / ((double)sData->total_points / 10000.f), 1.0f/axis); + + /* define final grid size using dim_factor, use min 3 for active axises */ + grid->x = (int)floor(tx / dim_factor); + CLAMP(grid->x, (dim[0]) ? 3 : 1, 100); + grid->y = (int)floor(ty / dim_factor); + CLAMP(grid->y, (dim[1]) ? 3 : 1, 100); + grid->z = (int)floor(tz / dim_factor); + CLAMP(grid->z, (dim[2]) ? 3 : 1, 100); + + grid_cells = grid->x*grid->y*grid->z; + + //printf("final grid size %i,%i,%i\n", grid->x, grid->y, grid->z); + + /* allocate memory for grids */ + + grid->bounds = MEM_callocN(sizeof(Bounds3D) * grid_cells, "Surface Grid Bounds"); + grid->s_pos = MEM_callocN(sizeof(int) * grid_cells, "Surface Grid Position"); + grid->s_num = MEM_callocN(sizeof(int) * grid_cells*num_of_threads, "Surface Grid Points"); + temp_s_num = MEM_callocN(sizeof(int) * grid_cells, "Temp Surface Grid Points"); + grid->t_index = MEM_callocN(sizeof(int) * sData->total_points, "Surface Grid Target Ids"); + temp_t_index = MEM_callocN(sizeof(int) * sData->total_points, "Temp Surface Grid Target Ids"); + + if (!grid->bounds || !grid->s_pos || !grid->s_num || !grid->t_index || !temp_s_num || !temp_t_index) + error = 1; + + if (!error) { + /* calculate number of points withing each cell */ + #pragma omp parallel for schedule(static) + for (index = 0; index < sData->total_points; index++) { + int x,y,z; + x = floor((bData->realCoord[bData->s_pos[index]].v[0] - grid->grid_bounds.min[0])/dim[0]*grid->x); + CLAMP(x, 0, grid->x-1); + y = floor((bData->realCoord[bData->s_pos[index]].v[1] - grid->grid_bounds.min[1])/dim[1]*grid->y); + CLAMP(y, 0, grid->y-1); + z = floor((bData->realCoord[bData->s_pos[index]].v[2] - grid->grid_bounds.min[2])/dim[2]*grid->z); + CLAMP(z, 0, grid->z-1); + + temp_t_index[index] = x + y * grid->x + z * grid->x*grid->y; +#ifdef _OPENMP + grid->s_num[temp_t_index[index]+omp_get_thread_num()*grid_cells]++; +#else + grid->s_num[temp_t_index[index]]++; +#endif + } + + /* for first cell only calc s_num */ + for (index = 1; index<num_of_threads; index++) { + grid->s_num[0] += grid->s_num[index*grid_cells]; + } + + /* calculate grid indexes */ + for (index = 1; index < grid_cells; index++) { + int id; + for (id = 1; id<num_of_threads; id++) { + grid->s_num[index] += grid->s_num[index+id*grid_cells]; + } + grid->s_pos[index] = grid->s_pos[index-1] + grid->s_num[index-1]; + } + + /* save point indexes to final array */ + for (index = 0; index < sData->total_points; index++) { + int pos = grid->s_pos[temp_t_index[index]] + temp_s_num[temp_t_index[index]]; + grid->t_index[pos] = index; + + temp_s_num[temp_t_index[index]]++; + } + + /* calculate cell bounds */ + { + int x; + #pragma omp parallel for schedule(static) + for (x=0; x<grid->x; x++) { + int y; + for (y=0; y<grid->y; y++) { + int z; + for (z=0; z<grid->z; z++) { + index = x + y * grid->x + z * grid->x*grid->y; + + /* set bounds */ + grid->bounds[index].min[0] = grid->grid_bounds.min[0] + dim[0]/grid->x*x; + grid->bounds[index].min[1] = grid->grid_bounds.min[1] + dim[1]/grid->y*y; + grid->bounds[index].min[2] = grid->grid_bounds.min[2] + dim[2]/grid->z*z; + + grid->bounds[index].max[0] = grid->grid_bounds.min[0] + dim[0]/grid->x*(x+1); + grid->bounds[index].max[1] = grid->grid_bounds.min[1] + dim[1]/grid->y*(y+1); + grid->bounds[index].max[2] = grid->grid_bounds.min[2] + dim[2]/grid->z*(z+1); + } + } + } + } + } + + if (temp_s_num) MEM_freeN(temp_s_num); + if (temp_t_index) MEM_freeN(temp_t_index); + + /* free per thread s_num values */ + grid->s_num = MEM_reallocN(grid->s_num, sizeof(int) * grid_cells); + + if (error || !grid->s_num) + freeGrid(sData); + } + + if (grid_bounds) MEM_freeN(grid_bounds); +} + /***************************** Freeing data ******************************/ /* Free brush data */ @@ -365,6 +629,23 @@ static void dynamicPaint_freeAdjData(PaintSurfaceData *data) } } +static void free_bakeData(PaintSurfaceData *data) +{ + PaintBakeData *bData = data->bData; + if (bData) { + if (bData->bNormal) MEM_freeN(bData->bNormal); + if (bData->s_pos) MEM_freeN(bData->s_pos); + if (bData->s_num) MEM_freeN(bData->s_num); + if (bData->realCoord) MEM_freeN(bData->realCoord); + if (bData->bNeighs) MEM_freeN(bData->bNeighs); + if (bData->grid) freeGrid(data); + if (bData->prev_verts) MEM_freeN(bData->prev_verts); + + MEM_freeN(data->bData); + data->bData = NULL; + } +} + static void dynamicPaint_freeSurfaceData(DynamicPaintSurface *surface) { PaintSurfaceData *data = surface->data; @@ -380,8 +661,12 @@ static void dynamicPaint_freeSurfaceData(DynamicPaintSurface *surface) } MEM_freeN(data->format_data); } + /* type data */ if (data->type_data) MEM_freeN(data->type_data); dynamicPaint_freeAdjData(data); + /* bake data */ + free_bakeData(data); + MEM_freeN(surface->data); surface->data = NULL; } @@ -648,9 +933,14 @@ static void dynamicPaint_allocateSurfaceType(DynamicPaintSurface *surface) if (sData->type_data == NULL) printError(surface->canvas, "Not enough free memory!"); } -static int surface_usesAdjData(DynamicPaintSurface *surface) { +static int surface_usesAdjDistance(DynamicPaintSurface *surface) { if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && surface->effect) return 1; if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) return 1; + return 0; +} + +static int surface_usesAdjData(DynamicPaintSurface *surface) { + if (surface_usesAdjDistance(surface)) return 1; if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX && surface->flags & MOD_DPAINT_ANTIALIAS) return 1; @@ -877,7 +1167,9 @@ static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, Scene *scene /* if read failed and we're on surface range do recalculate */ else if ((int)scene->r.cfra == current_frame) { /* calculate surface frame */ + canvas->flags |= MOD_DPAINT_BAKING; dynamicPaint_calculateFrame(surface, scene, ob, current_frame); + canvas->flags &= ~MOD_DPAINT_BAKING; BKE_ptcache_validate(cache, surface->current_frame); BKE_ptcache_write(&pid, surface->current_frame); @@ -1020,10 +1312,11 @@ struct DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, S else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) { MVert *mvert = result->getVertArray(result); int i; - float normal[3]; float* value = (float*)surface->data->type_data; + #pragma omp parallel for schedule(static) for (i=0; i<surface->data->total_points; i++) { + float normal[3]; normal_short_to_float_v3(normal, mvert[i].no); normalize_v3(normal); @@ -1112,10 +1405,11 @@ struct DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, S 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; + #pragma omp parallel for schedule(static) for (i=0; i<surface->data->total_points; i++) { + float normal[3]; normal_short_to_float_v3(normal, mvert[i].no); normalize_v3(normal); @@ -1358,7 +1652,7 @@ static int dynamicPaint_createUVSurface(DynamicPaintSurface *surface) 0.2f, 0.4f, 0.4f, -0.2f, -0.4f, 0.3f}; - int yy; + int ty; int w,h; int numOfFaces; char uvname[32]; @@ -1374,7 +1668,7 @@ static int dynamicPaint_createUVSurface(DynamicPaintSurface *surface) MVert *mvert = NULL; MFace *mface = NULL; MTFace *tface = NULL; - BB2d *faceBB = NULL; + Bounds2D *faceBB = NULL; int *final_index; int aa_samples; @@ -1422,23 +1716,23 @@ static int dynamicPaint_createUVSurface(DynamicPaintSurface *surface) * the pixel-inside-a-face search. */ if (!error) { - faceBB = (struct BB2d *) MEM_mallocN(numOfFaces*sizeof(struct BB2d), "MPCanvasFaceBB"); + faceBB = (struct Bounds2D *) MEM_mallocN(numOfFaces*sizeof(struct Bounds2D), "MPCanvasFaceBB"); if (!faceBB) error=1; } if (!error) - for (yy=0; yy<numOfFaces; yy++) { - int numOfVert = (mface[yy].v4) ? 4 : 3; + for (ty=0; ty<numOfFaces; ty++) { + int numOfVert = (mface[ty].v4) ? 4 : 3; int i; - VECCOPY2D(faceBB[yy].min, tface[yy].uv[0]); - VECCOPY2D(faceBB[yy].max, tface[yy].uv[0]); + VECCOPY2D(faceBB[ty].min, tface[ty].uv[0]); + VECCOPY2D(faceBB[ty].max, tface[ty].uv[0]); for (i = 1; i<numOfVert; i++) { - if (tface[yy].uv[i][0] < faceBB[yy].min[0]) faceBB[yy].min[0] = tface[yy].uv[i][0]; - if (tface[yy].uv[i][1] < faceBB[yy].min[1]) faceBB[yy].min[1] = tface[yy].uv[i][1]; - if (tface[yy].uv[i][0] > faceBB[yy].max[0]) faceBB[yy].max[0] = tface[yy].uv[i][0]; - if (tface[yy].uv[i][1] > faceBB[yy].max[1]) faceBB[yy].max[1] = tface[yy].uv[i][1]; + if (tface[ty].uv[i][0] < faceBB[ty].min[0]) faceBB[ty].min[0] = tface[ty].uv[i][0]; + if (tface[ty].uv[i][1] < faceBB[ty].min[1]) faceBB[ty].min[1] = tface[ty].uv[i][1]; + if (tface[ty].uv[i][0] > faceBB[ty].max[0]) faceBB[ty].max[0] = tface[ty].uv[i][0]; + if (tface[ty].uv[i][1] > faceBB[ty].max[1]) faceBB[ty].max[1] = tface[ty].uv[i][1]; } } @@ -1449,13 +1743,13 @@ static int dynamicPaint_createUVSurface(DynamicPaintSurface *surface) */ if (!error) { #pragma omp parallel for schedule(static) - for (yy = 0; yy < h; yy++) + for (ty = 0; ty < h; ty++) { - int xx; - for (xx = 0; xx < w; xx++) + int tx; + for (tx = 0; tx < w; tx++) { int i, sample; - int index = xx+w*yy; + int index = tx+w*ty; PaintUVPoint *tPoint = (&tempPoints[index]); short isInside = 0; /* if point is inside a uv face */ @@ -1469,24 +1763,24 @@ static int dynamicPaint_createUVSurface(DynamicPaintSurface *surface) 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; + point[0][0] = ((float)tx + 0.5f) / w; + point[0][1] = ((float)ty + 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; + point[1][0] = ((float)tx) / w; + point[1][1] = ((float)ty) / h; - point[2][0] = ((float)xx+1) / w; - point[2][1] = ((float)yy) / h; + point[2][0] = ((float)tx+1) / w; + point[2][1] = ((float)ty) / h; - point[3][0] = ((float)xx) / w; - point[3][1] = ((float)yy+1) / h; + point[3][0] = ((float)tx) / w; + point[3][1] = ((float)ty+1) / h; - point[4][0] = ((float)xx+1) / w; - point[4][1] = ((float)yy+1) / h; + point[4][0] = ((float)tx+1) / w; + point[4][1] = ((float)ty+1) / h; /* Loop through samples, starting from middle point */ @@ -1594,12 +1888,12 @@ static int dynamicPaint_createUVSurface(DynamicPaintSurface *surface) * (To avoid seams on uv island edges) */ #pragma omp parallel for schedule(static) - for (yy = 0; yy < h; yy++) + for (ty = 0; ty < h; ty++) { - int xx; - for (xx = 0; xx < w; xx++) + int tx; + for (tx = 0; tx < w; tx++) { - int index = xx+w*yy; + int index = tx+w*ty; PaintUVPoint *tPoint = (&tempPoints[index]); /* If point isnt't on canvas mesh */ @@ -1609,20 +1903,20 @@ static int dynamicPaint_createUVSurface(DynamicPaintSurface *surface) 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; + u_min = (tx > 0) ? -1 : 0; + u_max = (tx < (w-1)) ? 1 : 0; + v_min = (ty > 0) ? -1 : 0; + v_max = (ty < (h-1)) ? 1 : 0; - point[0] = ((float)xx + 0.5f) / w; - point[1] = ((float)yy + 0.5f) / h; + point[0] = ((float)tx + 0.5f) / w; + point[1] = ((float)ty + 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); + ind = (tx+u)+w*(ty+v); /* if neighbour has index */ if (tempPoints[ind].face_index != -1) { @@ -1672,12 +1966,12 @@ static int dynamicPaint_createUVSurface(DynamicPaintSurface *surface) * 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++) + for (ty = 0; ty < h; ty++) { - int xx; - for (xx = 0; xx < w; xx++) + int tx; + for (tx = 0; tx < w; tx++) { - int index = xx+w*yy; + int index = tx+w*ty; PaintUVPoint *tPoint = (&tempPoints[index]); if (tPoint->face_index == -1 && tPoint->neighbour_pixel != -1) tPoint->face_index = tempPoints[tPoint->neighbour_pixel].face_index; @@ -1685,7 +1979,6 @@ static int dynamicPaint_createUVSurface(DynamicPaintSurface *surface) } } - /* If any effect enabled, create surface effect / wet layer * neighbour lists. Processes possibly moving data. */ if (surface_usesAdjData(surface)) { @@ -1700,7 +1993,6 @@ static int dynamicPaint_createUVSurface(DynamicPaintSurface *surface) cursor++; } } - /* allocate memory */ sData->total_points = w*h; dynamicPaint_initAdjacencyData(surface); @@ -1709,12 +2001,12 @@ static int dynamicPaint_createUVSurface(DynamicPaintSurface *surface) PaintAdjData *ed = sData->adj_data; unsigned int n_pos = 0; //#pragma omp parallel for schedule(static) - for (yy = 0; yy < h; yy++) + for (ty = 0; ty < h; ty++) { - int xx; - for (xx = 0; xx < w; xx++) + int tx; + for (tx = 0; tx < w; tx++) { - int i, index = xx+w*yy; + int i, index = tx+w*ty; if (tempPoints[index].face_index != -1) { ed->n_index[final_index[index]] = n_pos; @@ -1724,7 +2016,7 @@ static int dynamicPaint_createUVSurface(DynamicPaintSurface *surface) /* 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); + int n_target = dynamicPaint_findNeighbourPixel(tempPoints, dm, uvname, w, h, tx, ty, i); if (n_target != -1) { ed->n_target[n_pos] = final_index[n_target]; @@ -1970,6 +2262,18 @@ static void dynamicPaint_updateMaterial(Material *mat, Scene *scene) if(tex->id.us && tex->type==TEX_VOXELDATA) { cache_voxeldata(tex, (int)scene->r.cfra); } + if(tex->id.us && tex->type==TEX_POINTDENSITY) { + /* set dummy values for render used */ + Render dummy_re = {0}; + dummy_re.scene = scene; + unit_m4(dummy_re.viewinv); + unit_m4(dummy_re.viewmat); + unit_m4(dummy_re.winmat); + dummy_re.winx = 128; + dummy_re.winy = 128; + cache_pointdensity(&dummy_re, tex); + } + /* 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) @@ -2648,6 +2952,15 @@ static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned } } +static int meshBrush_boundsIntersect(Bounds3D *b1, Bounds3D *b2, DynamicPaintBrushSettings *brush) +{ + if (brush->collision == MOD_DPAINT_COL_VOLUME) + return boundsIntersect(b1, b2); + else if (brush->collision == MOD_DPAINT_COL_DIST || brush->collision == MOD_DPAINT_COL_VOLDIST) + return boundsIntersectDist(b1, b2, brush->paint_distance); + else return 1; +} + #define VECADDVAL(v,val) {*(v)+=(val); *(v+1)+=(val); *(v+2)+=(val);} #define VECMULVAL(v,val) {*(v)*=(val); *(v+1)*=(val); *(v+2)*=(val);} @@ -2657,22 +2970,25 @@ static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned /* * Paint a brush object mesh to the surface */ -static int dynamicPaint_paintMesh(DynamicPaintSurface *surface, PaintBakeData *bData, DynamicPaintBrushSettings *brush, Object *canvasOb, Object *brushOb, float timescale) +static int dynamicPaint_paintMesh(DynamicPaintSurface *surface, DynamicPaintBrushSettings *brush, Object *canvasOb, Object *brushOb, float timescale) { + PaintSurfaceData *sData = surface->data; + PaintBakeData *bData = sData->bData; DerivedMesh *dm = NULL; MVert *mvert = NULL; MFace *mface = NULL; - PaintSurfaceData *sData = surface->data; if (!brush->dm) return 0; { BVHTreeFromMesh treeData = {0}; - int index; int numOfVerts; int ii; + Bounds3D mesh_bb; + VolumeGrid *grid = bData->grid; + /* * Transform collider vertices to world space * (Faster than transforming per pixel @@ -2685,251 +3001,278 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface, PaintBakeData *b for (ii=0; ii<numOfVerts; ii++) { mul_m4_v3(brushOb->obmat, mvert[ii].co); + + if (!ii) { + VECCOPY(mesh_bb.min, mvert[ii].co); + VECCOPY(mesh_bb.max, mvert[ii].co); + } + else + boundInsert(&mesh_bb, mvert[ii].co); } + /* check bounding box collision */ + if(grid && meshBrush_boundsIntersect(&grid->grid_bounds, &mesh_bb, brush)) /* Build a bvh tree from transformed vertices */ - bvhtree_from_mesh_faces(&treeData, dm, 0.0f, 4, 6); + if (bvhtree_from_mesh_faces(&treeData, dm, 0.0f, 4, 8)) + { + int c_index; + int total_cells = grid->x*grid->y*grid->z; - if(treeData.tree) { - #pragma omp parallel for schedule(static) - for (index = 0; index < sData->total_points; index++) - { - { - int ss, samples = bData->s_num[index]; - float total_sample = (float)samples; - float brushStrength = 0.0f; /* brush influence factor */ - float depth = 0.0f; /* displace depth */ + /* loop through space partitioning grid */ + for (c_index=0; c_index<total_cells; c_index++) { + int id; - float paintColor[3] = {0.0f}; - int numOfHits = 0; + /* check cell bounding box */ + if (!grid->s_num[c_index] || + !meshBrush_boundsIntersect(&grid->bounds[c_index], &mesh_bb, brush)) + continue; - /* for image sequence anti-aliasing, use gaussian factors */ - if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) - total_sample = gaussianTotal; + /* loop through cell points */ + #pragma omp parallel for schedule(static) + for (id = 0; id < grid->s_num[c_index]; id++) + { + int index = grid->t_index[grid->s_pos[c_index] + id]; - /* Supersampling */ - for (ss=0; ss<samples; ss++) + /*float color[3] = {1.0f, 0.0f, 0.0f}; + dynamicPaint_updatePointData(surface, index, brush, color, 1.0f, 0.0f, timescale); + continue;*/ { + int ss, samples = bData->s_num[index]; + float total_sample = (float)samples; + float brushStrength = 0.0f; /* brush influence factor */ + float depth = 0.0f; /* displace depth */ - float ray_start[3], ray_dir[3] = {0.0f}; - float colorband[4] = {0.0f}; - float sample_factor; - float sampleStrength = 0.0f; - BVHTreeRayHit hit; - BVHTreeNearest nearest; - short hit_found = 0; - - /* hit data */ - float hitCoord[3]; /* mid-sample hit coordinate */ - int hitFace = -1; /* mid-sample hit face */ - short hitQuad; /* mid-sample hit quad status */ + float paintColor[3] = {0.0f}; + int numOfHits = 0; - /* Supersampling factor */ + /* for image sequence anti-aliasing, use gaussian factors */ if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) - sample_factor = gaussianFactors[ss]; - else - sample_factor = 1.0f; - - /* Get current sample position in world coordinates */ - VECCOPY(ray_start, &bData->realCoord[(bData->s_index[index]+ss)*3]); - if (!(brush->flags & MOD_DPAINT_ACCEPT_NONCLOSED) || brush->ray_dir == MOD_DPAINT_RAY_CANVAS) { - VECCOPY(ray_dir, bData->bPoint[index].invNorm); - } - else /* MOD_DPAINT_RAY_ZPLUS */ - ray_dir[2] = 1.0f; + total_sample = gaussianTotal; - /* a simple hack to minimize change of ray leaks at identical ray - edge locations */ - VECADDVAL(ray_start, 0.001f); - - hit.index = -1; - hit.dist = 9999; - nearest.index = -1; - nearest.dist = brush->paint_distance * brush->paint_distance; /* find_nearest search uses squared distance */ - - /* Check volume collision */ - if (brush->collision == MOD_DPAINT_COL_VOLUME || brush->collision == MOD_DPAINT_COL_VOLDIST) - if(BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_dir, 0.0f, &hit, mesh_faces_spherecast_dp, &treeData) != -1) + /* Supersampling */ + for (ss=0; ss<samples; ss++) { - /* We hit a triangle, now check if collision point normal is facing the point */ + float ray_start[3], ray_dir[3] = {0.0f}; + float colorband[4] = {0.0f}; + float sample_factor; + float sampleStrength = 0.0f; + BVHTreeRayHit hit; + BVHTreeNearest nearest; + short hit_found = 0; + + /* hit data */ + float hitCoord[3]; /* mid-sample hit coordinate */ + int hitFace = -1; /* mid-sample hit face */ + short hitQuad; /* mid-sample hit quad status */ + + /* Supersampling factor */ + if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) + sample_factor = gaussianFactors[ss]; + else + sample_factor = 1.0f; + + /* Get current sample position in world coordinates */ + VECCOPY(ray_start, bData->realCoord[bData->s_pos[index]+ss].v); + if (!(brush->flags & MOD_DPAINT_ACCEPT_NONCLOSED) || brush->ray_dir == MOD_DPAINT_RAY_CANVAS) { + VECCOPY(ray_dir, bData->bNormal[index].invNorm); + } + else /* MOD_DPAINT_RAY_ZPLUS */ + ray_dir[2] = 1.0f; - /* For optimization sake, hit point normal isn't calculated in ray cast loop */ - int v1=mface[hit.index].v1, v2=mface[hit.index].v2, v3=mface[hit.index].v3, quad=(hit.no[0] == 1.0f); - float dot; + /* a simple hack to minimize change of ray leaks at identical ray - edge locations */ + VECADDVAL(ray_start, 0.001f); - if (quad) {v2=mface[hit.index].v3; v3=mface[hit.index].v4;} - - /* Get hit normal */ - normal_tri_v3( hit.no, mvert[v1].co, mvert[v2].co, mvert[v3].co); - dot = ray_dir[0]*hit.no[0] + ray_dir[1]*hit.no[1] + ray_dir[2]*hit.no[2]; + hit.index = -1; + hit.dist = 9999; + nearest.index = -1; + nearest.dist = brush->paint_distance * brush->paint_distance; /* find_nearest search uses squared distance */ - /* - * If ray and hit normal are facing same direction - * hit point is inside a closed mesh. - */ - if (dot>=0) + /* Check volume collision */ + if (brush->collision == MOD_DPAINT_COL_VOLUME || brush->collision == MOD_DPAINT_COL_VOLDIST) + if(BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_dir, 0.0f, &hit, mesh_faces_spherecast_dp, &treeData) != -1) { - float dist = hit.dist; - int f_index = hit.index; + /* We hit a triangle, now check if collision point normal is facing the point */ - /* In case of non-closed volumes, also cast a ray in opposite direction - * to make sure point is at least between two brush faces*/ - if (!(brush->flags & MOD_DPAINT_ACCEPT_NONCLOSED)) { - VECMULVAL(ray_dir, -1.0f); - hit.index = -1; - hit.dist = 9999; - BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_dir, 0.0f, &hit, mesh_faces_spherecast_dp, &treeData); - } + /* For optimization sake, hit point normal isn't calculated in ray cast loop */ + int v1=mface[hit.index].v1, v2=mface[hit.index].v2, v3=mface[hit.index].v3, quad=(hit.no[0] == 1.0f); + float dot; - if(hit.index != -1) { - /* Add factor on supersample filter */ - sampleStrength += sample_factor; - hit_found = HIT_VOLUME; - - /* - * Mark hit info - */ - VECADDFAC(hitCoord, ray_start, ray_dir, hit.dist); /* Calculate final hit coordinates */ - depth += dist*sample_factor; - hitFace = f_index; - hitQuad = quad; - } - } - } // end of raycast - - /* Check proximity collision */ - if ((brush->collision == MOD_DPAINT_COL_DIST || brush->collision == MOD_DPAINT_COL_VOLDIST) && - (!hit_found || (brush->flags & MOD_DPAINT_INVERSE_PROX))) - { - float proxDist = -1.0f; - float hitCo[3]; - short hQuad; - int face; + if (quad) {v2=mface[hit.index].v3; v3=mface[hit.index].v4;} + + /* Get hit normal */ + normal_tri_v3( hit.no, mvert[v1].co, mvert[v2].co, mvert[v3].co); + dot = ray_dir[0]*hit.no[0] + ray_dir[1]*hit.no[1] + ray_dir[2]*hit.no[2]; + + /* + * If ray and hit normal are facing same direction + * hit point is inside a closed mesh. + */ + if (dot>=0) + { + float dist = hit.dist; + int f_index = hit.index; - /* if inverse prox and no hit found, skip this sample */ - if (brush->flags & MOD_DPAINT_INVERSE_PROX && !hit_found) continue; + /* In case of non-closed volumes, also cast a ray in opposite direction + * to make sure point is at least between two brush faces*/ + if (!(brush->flags & MOD_DPAINT_ACCEPT_NONCLOSED)) { + VECMULVAL(ray_dir, -1.0f); + hit.index = -1; + hit.dist = 9999; - /* - * If pure distance proximity, find the nearest point on the mesh - */ - if (!(brush->flags & MOD_DPAINT_PROX_FACEALIGNED)) { - if (BLI_bvhtree_find_nearest(treeData.tree, ray_start, &nearest, mesh_faces_nearest_point_dp, &treeData) != -1) { - proxDist = sqrt(nearest.dist); /* find_nearest returns a squared distance, so gotta change it back to real distance */ - copy_v3_v3(hitCo, nearest.co); - hQuad = (nearest.no[0] == 1.0f); - face = nearest.index; - } - } - else { /* else cast a ray in surface normal direction */ - negate_v3(ray_dir); - hit.index = -1; - hit.dist = brush->paint_distance; + BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_dir, 0.0f, &hit, mesh_faces_spherecast_dp, &treeData); + } - /* Do a face normal directional raycast, and use that distance */ - if(BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_dir, 0.0f, &hit, mesh_faces_spherecast_dp, &treeData) != -1) - { - proxDist = hit.dist; - VECADDFAC(hitCo, ray_start, ray_dir, hit.dist); /* Calculate final hit coordinates */ - hQuad = (hit.no[0] == 1.0f); - face = hit.index; + if(hit.index != -1) { + /* Add factor on supersample filter */ + sampleStrength += sample_factor; + hit_found = HIT_VOLUME; + + /* + * Mark hit info + */ + VECADDFAC(hitCoord, ray_start, ray_dir, hit.dist); /* Calculate final hit coordinates */ + depth += dist*sample_factor; + hitFace = f_index; + hitQuad = quad; + } + } + } // end of raycast + + /* Check proximity collision */ + if ((brush->collision == MOD_DPAINT_COL_DIST || brush->collision == MOD_DPAINT_COL_VOLDIST) && + (!hit_found || (brush->flags & MOD_DPAINT_INVERSE_PROX))) + { + float proxDist = -1.0f; + float hitCo[3]; + short hQuad; + int face; + + /* if inverse prox and no hit found, skip this sample */ + if (brush->flags & MOD_DPAINT_INVERSE_PROX && !hit_found) continue; + + /* + * If pure distance proximity, find the nearest point on the mesh + */ + if (!(brush->flags & MOD_DPAINT_PROX_FACEALIGNED)) { + if (BLI_bvhtree_find_nearest(treeData.tree, ray_start, &nearest, mesh_faces_nearest_point_dp, &treeData) != -1) { + proxDist = sqrt(nearest.dist); /* find_nearest returns a squared distance, so gotta change it back to real distance */ + copy_v3_v3(hitCo, nearest.co); + hQuad = (nearest.no[0] == 1.0f); + face = nearest.index; + } + } + else { /* else cast a ray in surface normal direction */ + negate_v3(ray_dir); + hit.index = -1; + hit.dist = brush->paint_distance; + + /* Do a face normal directional raycast, and use that distance */ + if(BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_dir, 0.0f, &hit, mesh_faces_spherecast_dp, &treeData) != -1) + { + proxDist = hit.dist; + VECADDFAC(hitCo, ray_start, ray_dir, hit.dist); /* Calculate final hit coordinates */ + hQuad = (hit.no[0] == 1.0f); + face = hit.index; + } } - } - /* If a hit was found, calculate required values */ - if (proxDist >= 0.0f && proxDist <= brush->paint_distance) { - float dist_rate = proxDist / brush->paint_distance; - float prox_influence = 0.0f; + /* If a hit was found, calculate required values */ + if (proxDist >= 0.0f && proxDist <= brush->paint_distance) { + float dist_rate = proxDist / brush->paint_distance; + float prox_influence = 0.0f; - /* in case of inverse prox also undo volume effect */ - if (brush->flags & MOD_DPAINT_INVERSE_PROX) { - sampleStrength -= sample_factor; - dist_rate = 1.0f - dist_rate; - } + /* in case of inverse prox also undo volume effect */ + if (brush->flags & MOD_DPAINT_INVERSE_PROX) { + sampleStrength -= sample_factor; + dist_rate = 1.0f - dist_rate; + } - /* if using color ramp*/ - if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP && do_colorband(brush->paint_ramp, dist_rate, colorband)) - prox_influence = colorband[3]; - /* if using smooth falloff, multiply gaussian factor */ - else if (brush->proximity_falloff == MOD_DPAINT_PRFALL_SMOOTH) { - prox_influence = (1.0f - dist_rate) * sample_factor; - } - else prox_influence = (brush->flags & MOD_DPAINT_INVERSE_PROX) ? 0.0f : 1.0f; + /* if using color ramp*/ + if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP && do_colorband(brush->paint_ramp, dist_rate, colorband)) + prox_influence = colorband[3]; + /* if using smooth falloff, multiply gaussian factor */ + else if (brush->proximity_falloff == MOD_DPAINT_PRFALL_SMOOTH) { + prox_influence = (1.0f - dist_rate) * sample_factor; + } + else prox_influence = (brush->flags & MOD_DPAINT_INVERSE_PROX) ? 0.0f : 1.0f; - hit_found = HIT_PROXIMITY; - sampleStrength += prox_influence*sample_factor; + hit_found = HIT_PROXIMITY; + sampleStrength += prox_influence*sample_factor; - /* if no volume hit, use prox point face info */ - if (hitFace == -1) { - copy_v3_v3(hitCoord, hitCo); - hitQuad = hQuad; - hitFace = face; + /* if no volume hit, use prox point face info */ + if (hitFace == -1) { + copy_v3_v3(hitCoord, hitCo); + hitQuad = hQuad; + hitFace = face; + } } } - } - if (!hit_found) continue; + if (!hit_found) continue; - /* - * Process hit color and alpha - */ - if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) - { - float sampleColor[3]; - float alpha_factor = 1.0f; + /* + * Process hit color and alpha + */ + if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) + { + float sampleColor[3]; + float alpha_factor = 1.0f; - sampleColor[0] = brush->r; - sampleColor[1] = brush->g; - sampleColor[2] = brush->b; - - /* Get material+textures color on hit point if required */ - if (brush->flags & MOD_DPAINT_USE_MATERIAL) dynamicPaint_getMaterialColor(sampleColor, &alpha_factor, brushOb, &bData->realCoord[(bData->s_index[index]+ss)*3], hitCoord, hitFace, hitQuad, brush->dm, brush->mat); - - /* Sample colorband if required */ - if ((hit_found == HIT_PROXIMITY) && (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP)) { - if (!(brush->flags & MOD_DPAINT_RAMP_ALPHA)) { - sampleColor[0] = colorband[0]; - sampleColor[1] = colorband[1]; - sampleColor[2] = colorband[2]; + sampleColor[0] = brush->r; + sampleColor[1] = brush->g; + sampleColor[2] = brush->b; + + /* Get material+textures color on hit point if required */ + if (brush->flags & MOD_DPAINT_USE_MATERIAL) dynamicPaint_getMaterialColor(sampleColor, &alpha_factor, brushOb, bData->realCoord[bData->s_pos[index]+ss].v, hitCoord, hitFace, hitQuad, brush->dm, brush->mat); + + /* Sample colorband if required */ + if ((hit_found == HIT_PROXIMITY) && (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP)) { + if (!(brush->flags & MOD_DPAINT_RAMP_ALPHA)) { + sampleColor[0] = colorband[0]; + sampleColor[1] = colorband[1]; + sampleColor[2] = colorband[2]; + } } - } - /* Add AA sample */ - paintColor[0] += sampleColor[0]; - paintColor[1] += sampleColor[1]; - paintColor[2] += sampleColor[2]; - sampleStrength *= alpha_factor; - numOfHits++; - } + /* Add AA sample */ + paintColor[0] += sampleColor[0]; + paintColor[1] += sampleColor[1]; + paintColor[2] += sampleColor[2]; + sampleStrength *= alpha_factor; + numOfHits++; + } - /* apply sample strength */ - brushStrength += sampleStrength; - } // end supersampling + /* apply sample strength */ + brushStrength += sampleStrength; + } // end supersampling - /* if any sample was inside paint range */ - if (brushStrength > 0.01f) { + /* if any sample was inside paint range */ + if (brushStrength > 0.01f) { - /* apply supersampling results */ - if (samples > 1) { - brushStrength /= total_sample; - } - CLAMP(brushStrength, 0.0f, 1.0f); - - if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) { - /* Get final pixel color and alpha */ - paintColor[0] /= numOfHits; - paintColor[1] /= numOfHits; - paintColor[2] /= numOfHits; - paintColor[3] /= total_sample; - } - /* get final object space depth */ - else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE || - surface->type == MOD_DPAINT_SURFACE_T_WAVE) { - depth /= bData->bPoint[index].normal_scale * total_sample; + /* apply supersampling results */ + if (samples > 1) { + brushStrength /= total_sample; + } + CLAMP(brushStrength, 0.0f, 1.0f); + + if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) { + /* Get final pixel color and alpha */ + paintColor[0] /= numOfHits; + paintColor[1] /= numOfHits; + paintColor[2] /= numOfHits; + paintColor[3] /= total_sample; + } + /* get final object space depth */ + else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE || + surface->type == MOD_DPAINT_SURFACE_T_WAVE) { + depth /= bData->bNormal[index].normal_scale * total_sample; + } + + dynamicPaint_updatePointData(surface, index, brush, paintColor, brushStrength, depth, timescale); } - - dynamicPaint_updatePointData(surface, index, brush, paintColor, brushStrength, depth, timescale); } } } @@ -2946,18 +3289,26 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface, PaintBakeData *b /* * Paint a particle system to the surface */ -static int dynamicPaint_paintParticles(DynamicPaintSurface *surface, PaintBakeData *bData, ParticleSystem *psys, DynamicPaintBrushSettings *brush, Object *canvasOb, float timescale) +static int dynamicPaint_paintParticles(DynamicPaintSurface *surface, ParticleSystem *psys, DynamicPaintBrushSettings *brush, Object *canvasOb, float timescale) { - int index; ParticleSettings *part=psys->part; ParticleData *pa = NULL; PaintSurfaceData *sData = surface->data; + PaintBakeData *bData = sData->bData; + VolumeGrid *grid = bData->grid; KDTree *tree; int particlesAdded = 0; int invalidParticles = 0; int p = 0; + float solidradius = (brush->flags & MOD_DPAINT_PART_RAD) ? psys->part->size : brush->particle_radius; + float smooth = brush->particle_smooth; + + float range = solidradius + smooth; + + Bounds3D part_bb; + if (psys->totpart < 1) return 1; /* @@ -2977,7 +3328,19 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface, PaintBakeDa * For some reason they get past activity check, this should rule most of them out */ if (isnan(pa->state.co[0]) || isnan(pa->state.co[1]) || isnan(pa->state.co[2])) {invalidParticles++;continue;} + /* make sure particle is close enough to canvas */ + if (!boundIntersectPoint(&grid->grid_bounds, pa->state.co, range)) continue; + BLI_kdtree_insert(tree, p, pa->state.co, NULL); + + /* calc particle system bounds */ + if (particlesAdded == 0) { + VECCOPY(part_bb.min, pa->state.co); + VECCOPY(part_bb.max, pa->state.co); + } + else + boundInsert(&part_bb, pa->state.co); + particlesAdded++; } if (invalidParticles) @@ -2988,120 +3351,176 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface, PaintBakeDa BLI_kdtree_free(tree); return 1; } - /* balance tree */ - BLI_kdtree_balance(tree); - /* - * Loop through every surface point - */ - #pragma omp parallel for schedule(static) - for (index = 0; index < sData->total_points; index++) + /* only continue if particle bb is close enough to canvas bb */ + if (boundsIntersectDist(&grid->grid_bounds, &part_bb, range)) { - float disp_intersect = 0; - float radius; - float solidradius = brush->particle_radius; - float smooth = brush->particle_smooth; - float strength = 0.0f; - - /* If using per particle radius */ - if (brush->flags & MOD_DPAINT_PART_RAD) { - /* - * If we use per particle radius, we have to sample all particles - * within max radius range - */ - KDTreeNearest *nearest = NULL; - int n, particles = 0; - float range = psys->part->size + smooth; + int c_index; + int total_cells = grid->x*grid->y*grid->z; + int num_of_threads = 1; + + /* nearest particles search array for each thread */ + KDTreeNearest **nearest_th = NULL; + int nearest_limit = particlesAdded/10; + if (nearest_limit<10) nearest_limit = 10; + + /* balance tree */ + BLI_kdtree_balance(tree); - particles = BLI_kdtree_range_search(tree, range, &bData->realCoord[(bData->s_index[index])*3], NULL, &nearest); - for(n=0; n<particles; n++) { +#ifdef _OPENMP + num_of_threads = omp_get_max_threads(); +#endif + + nearest_th = MEM_callocN((num_of_threads)*sizeof(KDTreeNode*), "nearest_for_threads"); + + if (brush->flags & MOD_DPAINT_PART_RAD) + for (c_index=0; c_index<num_of_threads; c_index++) { + nearest_th[c_index] = MEM_callocN((nearest_limit)*sizeof(KDTreeNode), "dp_psys_treefoundstack"); + } + + /* loop through space partitioning grid */ + for (c_index=0; c_index<total_cells; c_index++) { + int id; + + /* check cell bounding box */ + if (!grid->s_num[c_index] || + !boundsIntersectDist(&grid->bounds[c_index], &part_bb, range)) + continue; + + /* loop through cell points */ + #pragma omp parallel for schedule(static) + for (id = 0; id < grid->s_num[c_index]; id++) + { + int index = grid->t_index[grid->s_pos[c_index] + id]; + float disp_intersect = 0.0f; + float radius = 0.0f; + float strength = 0.0f; /* - * Find particle that produces highest influence + * With predefined radius, there is no variation between particles. + * It's enough to just find the nearest one. */ - ParticleData *pa = psys->particles + nearest[n].index; - float rad = pa->size + smooth; - float str,smooth_range; + { + KDTreeNearest nearest; + float smooth_range; + radius = solidradius + smooth; + + /* Find nearest particle and get distance to it */ + BLI_kdtree_find_nearest(tree, bData->realCoord[bData->s_pos[index]].v, NULL, &nearest); + if (nearest.dist > radius) continue; + + /* distances inside solid radius have maximum influence -> dist = 0 */ + smooth_range = (nearest.dist - solidradius); + if (smooth_range<0) smooth_range=0.0f; + /* do smoothness if enabled */ + if (smooth) smooth_range/=smooth; + + strength = 1.0f - smooth_range; + disp_intersect = radius - nearest.dist; + } + /* If using random per particle radius and closest particle didn't give max influence */ + if (brush->flags & MOD_DPAINT_PART_RAD && strength < 1.0f && psys->part->randsize > 0.0f) { + /* + * If we use per particle radius, we have to sample all particles + * within max radius range + */ +#ifdef _OPENMP + KDTreeNearest *nearest = nearest_th[omp_get_thread_num()]; +#else + KDTreeNearest *nearest = nearest_th[0]; +#endif + int n, particles = 0; + float smooth_range = range, dist; + /* calculate max range that can have particles with higher influence than the nearest one */ + float max_range = smooth - strength*smooth + solidradius; - if (nearest[n].dist > rad) continue; /* if outside range, continue to next one */ + particles = BLI_kdtree_range_search_thread_safe(tree, max_range, bData->realCoord[bData->s_pos[index]].v, NULL, nearest, nearest_limit); - if ((rad-nearest[n].dist) > disp_intersect) { - disp_intersect = rad-nearest[n].dist; - radius = rad; - } + /* Find particle that produces highest influence */ + for(n=0; n<particles; n++) { + ParticleData *pa = psys->particles + nearest[n].index; + float s_range; - /* Continue with paint check */ - if (nearest[n].dist < pa->size) { - /* If particle is inside the solid range, no need to continue further - * since no other particle can have higher influence */ - strength = 1.0f; - break; - } - smooth_range = (nearest[n].dist - pa->size); + /* skip if out of range */ + if (nearest[n].dist > (pa->size + smooth)) + continue; - /* do smoothness if enabled */ - if (smooth) smooth_range/=smooth; - str = 1.0f - smooth_range; - /* if influence is greater, use this one */ - if (str > strength) strength = str; + /* update hit data */ + s_range = nearest[n].dist - pa->size; - } - if (nearest) MEM_freeN(nearest); + /* continue if higher influence is already found */ + if (smooth_range < s_range) + continue; - } - else { - /* - * With predefined radius, there is no variation between particles. - * It's enough to just find the nearest one. - */ - KDTreeNearest nearest; - float smooth_range; - radius = solidradius + smooth; - - /* Find nearest particle and get distance to it */ - BLI_kdtree_find_nearest(tree, &bData->realCoord[(bData->s_index[index])*3], NULL, &nearest); - if (nearest.dist > radius) continue; - - /* distances inside solid radius have maximum influence -> dist = 0 */ - smooth_range = (nearest.dist - solidradius); - if (smooth_range<0) smooth_range=0.0f; - /* do smoothness if enabled */ - if (smooth) smooth_range/=smooth; - - strength = 1.0f - smooth_range; - disp_intersect = radius - nearest.dist; - } + /* update hit data */ + smooth_range = s_range; + dist = nearest[n].dist; - if (strength > 0.001f) - { - float paintColor[4] = {0.0f}; - float depth = 0.0f; + /* If inside solid range and no disp depth required, no need to seek further */ + if (s_range < 0.0f) + if (surface->type != MOD_DPAINT_SURFACE_T_DISPLACE && + surface->type != MOD_DPAINT_SURFACE_T_WAVE) + break; + } - if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) { - paintColor[0] = brush->r; - paintColor[1] = brush->g; - paintColor[2] = brush->b; - } - else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE || - surface->type == MOD_DPAINT_SURFACE_T_WAVE) { - /* get displace depth */ - disp_intersect = (1.0f - sqrt(disp_intersect / radius)) * radius; - depth = (radius - disp_intersect) / bData->bPoint[index].normal_scale; - if (depth<0.0f) depth = 0.0f; + /* now calculate influence for this particle */ + if (smooth_range != range) { + float rad = radius + smooth, str; + + if ((rad-dist) > disp_intersect) { + disp_intersect = dist; + radius = rad; + } + + /* do smoothness if enabled */ + if (smooth) smooth_range/=smooth; + str = 1.0f - smooth_range; + /* if influence is greater, use this one */ + if (str > strength) strength = str; + } + + } + + if (strength > 0.001f) + { + float paintColor[4] = {0.0f}; + float depth = 0.0f; + + if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) { + paintColor[0] = brush->r; + paintColor[1] = brush->g; + paintColor[2] = brush->b; + } + else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE || + surface->type == MOD_DPAINT_SURFACE_T_WAVE) { + /* get displace depth */ + disp_intersect = (1.0f - sqrt(disp_intersect / radius)) * radius; + depth = (radius - disp_intersect) / bData->bNormal[index].normal_scale; + if (depth<0.0f) depth = 0.0f; + } + + dynamicPaint_updatePointData(surface, index, brush, paintColor, strength, depth, timescale); + } } - - dynamicPaint_updatePointData(surface, index, brush, paintColor, strength, depth, timescale); } + + /* free nearest array */ + if (brush->flags & MOD_DPAINT_PART_RAD) + for (c_index=0; c_index<num_of_threads; c_index++) { + if (nearest_th[c_index]) MEM_freeN(nearest_th[c_index]); + } + if (nearest_th) MEM_freeN(nearest_th); } BLI_kdtree_free(tree); return 1; } -static int dynamicPaint_paintSinglePoint(DynamicPaintSurface *surface, PaintBakeData *bData, float *pointCoord, DynamicPaintBrushSettings *brush, Object *canvasOb, float timescale) +static int dynamicPaint_paintSinglePoint(DynamicPaintSurface *surface, float *pointCoord, DynamicPaintBrushSettings *brush, Object *canvasOb, float timescale) { int index; PaintSurfaceData *sData = surface->data; + PaintBakeData *bData = sData->bData; /* * Loop through every surface point @@ -3109,7 +3528,7 @@ static int dynamicPaint_paintSinglePoint(DynamicPaintSurface *surface, PaintBake #pragma omp parallel for schedule(static) for (index = 0; index < sData->total_points; index++) { - float distance = len_v3v3(pointCoord, &bData->realCoord[(bData->s_index[index])*3]); + float distance = len_v3v3(pointCoord, bData->realCoord[bData->s_pos[index]].v); float colorband[4] = {0.0f}; float strength; @@ -3149,7 +3568,7 @@ static int dynamicPaint_paintSinglePoint(DynamicPaintSurface *surface, PaintBake surface->type == MOD_DPAINT_SURFACE_T_WAVE) { /* get displace depth */ float disp_intersect = (1.0f - sqrt((brush->paint_distance-distance) / brush->paint_distance)) * brush->paint_distance; - depth = (brush->paint_distance - disp_intersect) / bData->bPoint[index].normal_scale; + depth = (brush->paint_distance - disp_intersect) / bData->bNormal[index].normal_scale; if (depth<0.0f) depth = 0.0f; } dynamicPaint_updatePointData(surface, index, brush, paintColor, strength, depth, timescale); @@ -3167,23 +3586,32 @@ static int dynamicPaint_paintSinglePoint(DynamicPaintSurface *surface, PaintBake * Calculate current frame neighbouring point distances * and direction vectors */ -static void dynamicPaint_prepareNeighbourData(DynamicPaintSurface *surface, BakeNeighPoint *bNeighs, float *realCoords) +static void dynamicPaint_prepareNeighbourData(DynamicPaintSurface *surface) { PaintSurfaceData *sData = surface->data; + PaintBakeData *bData = sData->bData; + BakeNeighPoint *bNeighs; + PaintAdjData *adj_data = sData->adj_data; + Vec3f *realCoord = bData->realCoord; int index; + if (!surface_usesAdjDistance(surface) || !sData->adj_data) return; + + bNeighs = bData->bNeighs = MEM_mallocN(sData->adj_data->total_targets*sizeof(struct BakeNeighPoint),"PaintEffectBake"); + if (!bNeighs) return; + #pragma omp parallel for schedule(static) for (index = 0; index < sData->total_points; index++) { int i; - int numOfNeighs = sData->adj_data->n_num[index]; + int numOfNeighs = adj_data->n_num[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]; + int n_index = adj_data->n_index[index]+i; + int t_index = adj_data->n_target[n_index]; /* dir vec */ - sub_v3_v3v3(bNeighs[n_index].dir, &realCoords[t_index*3], &realCoords[index*3]); + sub_v3_v3v3(bNeighs[n_index].dir, realCoord[bData->s_pos[t_index]].v, realCoord[bData->s_pos[index]].v); /* dist */ bNeighs[n_index].dist = len_v3(bNeighs[n_index].dir); /* normalize dir */ @@ -3199,7 +3627,7 @@ static void dynamicPaint_prepareNeighbourData(DynamicPaintSurface *surface, Bake * Prepare data required by effects for current frame. * Returns number of steps required */ -static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *scene, Object *ob, BakeNeighPoint *bNeighs, float **force, float *realCoords, float timescale) +static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *scene, Object *ob, float **force, float timescale) { double average_dist = 0.0f; double average_force = 0.0f; @@ -3207,6 +3635,9 @@ static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *s float fastest_effect; int steps; PaintSurfaceData *sData = surface->data; + PaintBakeData *bData = sData->bData; + BakeNeighPoint *bNeighs = bData->bNeighs; + Vec3f *realCoord = bData->realCoord; int index; /* Init force data if required */ @@ -3226,7 +3657,7 @@ static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *s /* apply force fields */ if (effectors) { EffectedPoint epoint; - pd_point_from_loc(scene, &realCoords[index*3], vel, index, &epoint); + pd_point_from_loc(scene, realCoord[bData->s_pos[index]].v, vel, index, &epoint); epoint.vel_to_sec = 1.0f; pdDoEffectors(effectors, NULL, surface->effector_weights, &epoint, forc, NULL); } @@ -3286,9 +3717,10 @@ static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *s /* * Processes active effect step. */ -static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, BakeNeighPoint *bNeighs, float *force, PaintPoint *prevPoint, float timescale) +static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, float *force, PaintPoint *prevPoint, float timescale) { PaintSurfaceData *sData = surface->data; + BakeNeighPoint *bNeighs = sData->bData->bNeighs; int index; if (!sData->adj_data) return; @@ -3484,7 +3916,7 @@ static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, BakeNeighPoi if (dir_factor > 1.0f) dir_factor = 1.0f; /* mix new color */ - mixColors(ePoint->e_color, ePoint->e_alpha, pPoint->e_color, dir_factor); + if (dir_factor) mixColors(ePoint->e_color, ePoint->e_alpha, pPoint->e_color, dir_factor); ePoint->e_alpha += dir_factor; ePoint->wetness += dir_factor; @@ -3513,9 +3945,10 @@ static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, BakeNeighPoi #define WAVE_TIME_FAC 0.1 -void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, BakeNeighPoint *bNeighs, float timescale) +void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescale) { PaintSurfaceData *sData = surface->data; + BakeNeighPoint *bNeighs = sData->bData->bNeighs; int index; int steps, ss; float dt, min_dist, damp_factor; @@ -3620,57 +4053,11 @@ void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, BakeNeighPoint *bNeig #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 */ -static int dynamicPaint_prepareSurfaceStep(DynamicPaintSurface *surface, PaintBakeData *bData, Object *ob, DerivedMesh *dm, float timescale) { +/* Do dissolve and fading effects */ +static void dynamicPaint_surfacePreStep(DynamicPaintSurface *surface, float timescale) { PaintSurfaceData *sData = surface->data; - - MVert *mvert = dm->getVertArray(dm); - MFace *mface = dm->getFaceArray(dm); - int index; - FaceAdv *canvas_inv_normals = NULL; - Vec3f *canvas_verts = NULL; - - int canvasNumOfVerts = dm->getNumVerts(dm); - int canvasNumOfFaces = dm->getNumFaces(dm); - - /* - * Make a transformed copy of canvas derived mesh vertices to avoid recalculation. - */ - 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(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) - */ - 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( 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); - } - /* - * Prepare each surface point for a new step - */ #pragma omp parallel for schedule(static) for (index=0; index<sData->total_points; index++) { @@ -3680,7 +4067,7 @@ static int dynamicPaint_prepareSurfaceStep(DynamicPaintSurface *surface, PaintBa /* drying */ if (pPoint->wetness > 0.0f) { /* for every drying step blend wet paint to the background */ - mixColors(pPoint->color, pPoint->alpha, pPoint->e_color, pPoint->e_alpha); + if (pPoint->e_alpha) mixColors(pPoint->color, pPoint->alpha, pPoint->e_color, pPoint->e_alpha); pPoint->state = 1; /* only increase alpha if wet paint has higher */ @@ -3715,7 +4102,105 @@ static int dynamicPaint_prepareSurfaceStep(DynamicPaintSurface *surface, PaintBa VALUE_DISSOLVE(*point, surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG)); if (*point < 0.0f) *point = 0.0f; } + } +} + +static int dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *ob) +{ + PaintSurfaceData *sData = surface->data; + PaintBakeData *bData = sData->bData; + DerivedMesh *dm = surface->canvas->dm; + MVert *mvert = dm->getVertArray(dm); + + int numOfVerts = dm->getNumVerts(dm); + int i; + int ret = 0; + + if (!bData->prev_verts) return 1; + + /* matrix */ + for (i=0; i<4; i++) { + int j; + for (j=0; j<4; j++) + if (bData->prev_obmat[i][j] != ob->obmat[i][j]) return 1; + } + + /* vertices */ + #pragma omp parallel for schedule(static) + for (i=0; i<numOfVerts; i++) { + int j; + for (j=0; j<3; j++) + if (bData->prev_verts[i].co[j] != mvert[i].co[j]) { + ret = 1; + break; + } + } + + return 0; +} + +/* Prepare for surface step by creating PaintBakeNormal data */ +static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, Object *ob) +{ + PaintSurfaceData *sData = surface->data; + PaintAdjData *adj_data = sData->adj_data; + PaintBakeData *bData = sData->bData; + DerivedMesh *dm = surface->canvas->dm; + int index; + + int canvasNumOfVerts = dm->getNumVerts(dm); + MVert *mvert = dm->getVertArray(dm); + Vec3f *canvas_verts; + + /* if previous data exists and mesh hasn't moved, no need to recalc */ + if (bData && !dynamicPaint_surfaceHasMoved(surface, ob)) return 1; + + canvas_verts = (struct Vec3f *) MEM_mallocN(canvasNumOfVerts*sizeof(struct Vec3f), "Dynamic Paint transformed canvas verts"); + if (!canvas_verts) return 0; + + /* alloc memory if required */ + if (!bData) { + sData->bData = bData = (struct PaintBakeData *) MEM_callocN(sizeof(struct PaintBakeData), "Dynamic Paint bake data"); + if (!bData) { + if (canvas_verts) MEM_freeN(canvas_verts); + return 0; + } + + /* Init bdata */ + bData->bNormal = (struct PaintBakeNormal *) MEM_mallocN(sData->total_points*sizeof(struct PaintBakeNormal), "Dynamic Paint step data"); + bData->s_pos = MEM_mallocN(sData->total_points*sizeof(unsigned int), "Dynamic Paint bData s_pos"); + bData->s_num = MEM_mallocN(sData->total_points*sizeof(unsigned int), "Dynamic Paint bData s_num"); + bData->realCoord = (struct Vec3f *) MEM_mallocN(surface_totalSamples(surface)*sizeof(Vec3f), "Dynamic Paint point coords"); + bData->prev_verts = MEM_mallocN(canvasNumOfVerts*sizeof(MVert), "Dynamic Paint bData prev_verts"); + + if (!bData->bNormal || !bData->s_pos || !bData->s_num || !bData->realCoord || !canvas_verts) { + if (bData->bNormal) MEM_freeN(bData->bNormal); + if (bData->s_pos) MEM_freeN(bData->s_pos); + if (bData->s_num) MEM_freeN(bData->s_num); + if (bData->realCoord) MEM_freeN(bData->realCoord); + if (canvas_verts) MEM_freeN(canvas_verts); + + return printError(surface->canvas, "Not enough free memory."); + } + } + + /* + * Make a transformed copy of canvas derived mesh vertices to avoid recalculation. + */ + #pragma omp parallel for schedule(static) + for (index=0; index<canvasNumOfVerts; index++) { + /* Multiply coordinates by canvas transformation matrix */ + VECCOPY(canvas_verts[index].v, mvert[index].co); + mul_m4_v3(ob->obmat, canvas_verts[index].v); + } + + /* + * Prepare each surface point for a new step + */ + #pragma omp parallel for schedule(static) + for (index=0; index<sData->total_points; index++) + { /* * Calculate current 3D-position of each surface pixel */ @@ -3726,87 +4211,89 @@ static int dynamicPaint_prepareSurfaceStep(DynamicPaintSurface *surface, PaintBa int ss; bData->s_num[index] = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1; - bData->s_index[index] = index * bData->s_num[index]; + bData->s_pos[index] = index * bData->s_num[index]; /* per sample coordinates */ for (ss=0; ss<bData->s_num[index]; ss++) { - interp_v3_v3v3v3( &bData->realCoord[(bData->s_index[index]+ss)*3], + interp_v3_v3v3v3( bData->realCoord[bData->s_pos[index]+ss].v, canvas_verts[tPoint->v1].v, canvas_verts[tPoint->v2].v, canvas_verts[tPoint->v3].v, f_data->barycentricWeights[index*bData->s_num[index]+ss].v); } /* Calculate current pixel surface normal */ - if(mface[tPoint->face_index].flag & ME_SMOOTH) { - normal_short_to_float_v3(n1, mvert[tPoint->v1].no); - normal_short_to_float_v3(n2, mvert[tPoint->v2].no); - normal_short_to_float_v3(n3, mvert[tPoint->v3].no); - - interp_v3_v3v3v3( bData->bPoint[index].invNorm, - n1, n2, n3, f_data->barycentricWeights[index*bData->s_num[index]].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, canvas_inv_normals[tPoint->face_index].no_q);} - else {VECCOPY(bData->bPoint[index].invNorm, canvas_inv_normals[tPoint->face_index].no);} - } + normal_short_to_float_v3(n1, mvert[tPoint->v1].no); + normal_short_to_float_v3(n2, mvert[tPoint->v2].no); + normal_short_to_float_v3(n3, mvert[tPoint->v3].no); + + interp_v3_v3v3v3( bData->bNormal[index].invNorm, + n1, n2, n3, f_data->barycentricWeights[index*bData->s_num[index]].v); + mul_mat3_m4_v3(ob->obmat, bData->bNormal[index].invNorm); + normalize_v3(bData->bNormal[index].invNorm); + negate_v3(bData->bNormal[index].invNorm); } else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) { /* In case of verted data */ int ss; - if (surface->flags & MOD_DPAINT_ANTIALIAS && sData->adj_data) { - bData->s_num[index] = sData->adj_data->n_num[index]+1; - bData->s_index[index] = sData->adj_data->n_index[index]+index; + if (surface->flags & MOD_DPAINT_ANTIALIAS && adj_data) { + bData->s_num[index] = adj_data->n_num[index]+1; + bData->s_pos[index] = adj_data->n_index[index]+index; } else { bData->s_num[index] = 1; - bData->s_index[index] = index; + bData->s_pos[index] = index; } /* per sample coordinates */ for (ss=0; ss<bData->s_num[index]; ss++) { /* first sample is always point center */ - VECCOPY(&bData->realCoord[(bData->s_index[index]+ss)*3], canvas_verts[index].v); + VECCOPY(bData->realCoord[bData->s_pos[index]+ss].v, canvas_verts[index].v); if (ss > 0) { - int t_index = sData->adj_data->n_index[index]+(ss-1); + int t_index = adj_data->n_index[index]+(ss-1); /* get vertex position at 1/3 of each neigh edge */ - mul_v3_fl(&bData->realCoord[(bData->s_index[index]+ss)*3], 2.0f/3.0f); - madd_v3_v3fl(&bData->realCoord[(bData->s_index[index]+ss)*3], canvas_verts[sData->adj_data->n_target[t_index]].v, 1.0f/3.0f); + mul_v3_fl(bData->realCoord[bData->s_pos[index]+ss].v, 2.0f/3.0f); + madd_v3_v3fl(bData->realCoord[bData->s_pos[index]+ss].v, canvas_verts[adj_data->n_target[t_index]].v, 1.0f/3.0f); } } - /* location, currently vertex format can have only one sample */ /* normal */ - normal_short_to_float_v3(bData->bPoint[index].invNorm, mvert[index].no); - mul_mat3_m4_v3(ob->obmat, bData->bPoint[index].invNorm); - normalize_v3(bData->bPoint[index].invNorm); - //mul_qt_v3(ob->quat, bPoint[index].invNorm); - negate_v3(bData->bPoint[index].invNorm); + normal_short_to_float_v3(bData->bNormal[index].invNorm, mvert[index].no); + mul_mat3_m4_v3(ob->obmat, bData->bNormal[index].invNorm); + normalize_v3(bData->bNormal[index].invNorm); + negate_v3(bData->bNormal[index].invNorm); } /* Prepare special data for surface types */ 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); - normalize_v3(temp_nor);} - else {temp_nor[0]=0.0f;temp_nor[1]=0.0f;temp_nor[2]=1.0f;} + if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) { + normal_short_to_float_v3(temp_nor, mvert[index].no); + normalize_v3(temp_nor); + } + else { + temp_nor[0]=0.0f; + temp_nor[1]=0.0f; + temp_nor[2]=1.0f; + } mul_v3_v3 (temp_nor, ob->size); - bData->bPoint[index].normal_scale = len_v3(temp_nor); + bData->bNormal[index].normal_scale = len_v3(temp_nor); } - - /* - * TODO: paint effect space preparation - */ } MEM_freeN(canvas_verts); - MEM_freeN(canvas_inv_normals); + + /* generate surface space partitioning grid */ + surfaceGenerateGrid(surface); + + /* calculate current frame neighbouring point distances and global dirs */ + dynamicPaint_prepareNeighbourData(surface); + + /* Copy current frame position to check against in next frame */ + copy_m4_m4(bData->prev_obmat, ob->obmat); + memcpy(bData->prev_verts, mvert, canvasNumOfVerts*sizeof(MVert)); return 1; } @@ -3849,81 +4336,22 @@ static void scene_setSubframe(Scene *scene, float subframe) scene->r.subframe = subframe; } -static int surface_totalSamples(DynamicPaintSurface *surface) -{ - if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ && - surface->flags & MOD_DPAINT_ANTIALIAS) - return (surface->data->total_points*5); - if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX && - surface->flags & MOD_DPAINT_ANTIALIAS && surface->data->adj_data) - return (surface->data->total_points+surface->data->adj_data->total_targets); - - return surface->data->total_points; -} - -static void free_bDataSamples(DynamicPaintSurface *surface, PaintBakeData *bData) -{ - PaintSurfaceData *sData = surface->data; - float *old_realCoord = bData->realCoord; - if (!old_realCoord) return; - - /* if no anti-aliasing enabled, data is alredy in right order */ - if (surface->flags & MOD_DPAINT_ANTIALIAS) { - bData->realCoord = (float *) MEM_mallocN(3*sData->total_points*sizeof(float), "Dynamic Paint point coords"); - - if (bData->realCoord) { - int index; - - #pragma omp parallel for schedule(static) - for (index=0; index<sData->total_points; index++) - { - memcpy(&bData->realCoord[index*3], &old_realCoord[(bData->s_index[index])*3], sizeof(float)*3); - } - } - MEM_freeN(old_realCoord); - } - - /* also free indexing data */ - MEM_freeN(bData->s_index); - MEM_freeN(bData->s_num); - bData->s_index = NULL; - bData->s_num = NULL; -} - /* * Do Dynamic Paint Step. Paints scene brush objects of current state/frame to canvas. */ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *surface, float timescale, float subframe) { PaintSurfaceData *sData = surface->data; + PaintBakeData *bData = sData->bData; DynamicPaintCanvasSettings *canvas = surface->canvas; - PaintBakeData bData; int ret = 1; if (!sData || sData->total_points < 1) return 0; - /* Init surface current frame position data */ - bData.bPoint = (struct PaintBakePoint *) MEM_mallocN(sData->total_points*sizeof(struct PaintBakePoint), "Dynamic Paint step data"); - bData.s_index = MEM_mallocN(sData->total_points*sizeof(unsigned int), "Dynamic Paint bData s_index"); - bData.s_num = MEM_mallocN(sData->total_points*sizeof(unsigned int), "Dynamic Paint bData s_num"); - bData.realCoord = (float *) MEM_mallocN(3*surface_totalSamples(surface)*sizeof(float), "Dynamic Paint point coords"); - if (!bData.bPoint || !bData.s_index || !bData.s_num || !bData.realCoord) { - if (bData.bPoint) MEM_freeN(bData.bPoint); - if (bData.s_index) MEM_freeN(bData.s_index); - if (bData.s_num) MEM_freeN(bData.s_num); - if (bData.realCoord) MEM_freeN(bData.realCoord); - - return printError(canvas, "Not enough free memory."); - } - - if (!dynamicPaint_prepareSurfaceStep(surface, &bData, ob, canvas->dm, timescale)) { - ret = 0; - printError(canvas, "Not enough free memory."); - } + dynamicPaint_surfacePreStep(surface, timescale); /* * Loop through surface's target paint objects and do painting */ - else { Base *base = NULL; GroupObject *go = NULL; @@ -3997,15 +4425,15 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su /* 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); + dynamicPaint_paintParticles(surface, brush->psys, brush, ob, timescale); } } else if (brush->collision == MOD_DPAINT_COL_POINT && brushObj != ob) { - dynamicPaint_paintSinglePoint(surface, &bData, brushObj->loc, brush, ob, timescale); + dynamicPaint_paintSinglePoint(surface, brushObj->loc, brush, ob, timescale); } else if (brushObj != ob){ /* Paint a mesh */ - dynamicPaint_paintMesh(surface, &bData, brush, ob, brushObj, timescale); + dynamicPaint_paintMesh(surface, brush, ob, brushObj, timescale); } /* return object to it's original state */ @@ -4020,69 +4448,45 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su } } - if (bData.bPoint) MEM_freeN(bData.bPoint); - bData.bPoint = NULL; - - /* neighbour data and surface opretions that use it */ - if (sData->adj_data) + /* surfaces operations that use adjacency data */ + if (sData->adj_data && bData->bNeighs) { - BakeNeighPoint *bNeighs = MEM_mallocN(sData->adj_data->total_targets*sizeof(struct BakeNeighPoint), "PaintEffectBake"); - - if (bNeighs) { - /* free antialias sample coords, as they're not needed anymore - * and re-order data*/ - free_bDataSamples(surface, &bData); - /* calculate current frame distances and global dirs */ - dynamicPaint_prepareNeighbourData(surface, bNeighs, bData.realCoord); - - /* wave type surface simulation step */ - if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) { - dynamicPaint_doWaveStep(surface, bNeighs, timescale); - } - - /* paint movement effects */ - if (surface->effect && surface->type == MOD_DPAINT_SURFACE_T_PAINT) - { - int steps = 1, s; - PaintPoint *prevPoint; - float *force = NULL; - - /* 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 || !bData.realCoord) { - if (bData.realCoord) MEM_freeN(bData.realCoord); - if (prevPoint) MEM_freeN(prevPoint); - if (bNeighs) MEM_freeN(bNeighs); + /* wave type surface simulation step */ + if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) { + dynamicPaint_doWaveStep(surface, 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, bNeighs, &force, bData.realCoord, timescale); + /* Allocate memory for surface previous points to read unchanged values from */ + prevPoint = MEM_mallocN(sData->total_points*sizeof(struct PaintPoint), "PaintSurfaceDataCopy"); + if (!prevPoint) { + if (prevPoint) MEM_freeN(prevPoint); + return printError(canvas, "Not enough free memory."); + } - /* - * Do Effects steps - */ - for (s = 0; s < steps; s++) - { - dynamicPaint_doEffectStep(surface, bNeighs, force, prevPoint, timescale/(float)steps); - } + /* Prepare effects and get number of required steps */ + steps = dynamicPaint_prepareEffectStep(surface, scene, ob, &force, timescale); - /* Free temporary effect data */ - if (prevPoint) MEM_freeN(prevPoint); - if (force) MEM_freeN(force); + /* + * Do Effects steps + */ + for (s = 0; s < steps; s++) + { + dynamicPaint_doEffectStep(surface, force, prevPoint, timescale/(float)steps); } - MEM_freeN(bNeighs); + /* Free temporary effect data */ + if (prevPoint) MEM_freeN(prevPoint); + if (force) MEM_freeN(force); } } - if (bData.realCoord) MEM_freeN(bData.realCoord); - if (bData.s_index) MEM_freeN(bData.s_index); - if (bData.s_num) MEM_freeN(bData.s_num); - return ret; } @@ -4092,6 +4496,10 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su static int dynamicPaint_calculateFrame(DynamicPaintSurface *surface, Scene *scene, Object *cObject, int frame) { float timescale = 1.0f; + int ret; + + /* update bake data */ + dynamicPaint_generateBakeData(surface, cObject); /* dont do substeps for first frame */ if (surface->substeps && (frame != surface->start_frame)) { @@ -4106,8 +4514,9 @@ static int dynamicPaint_calculateFrame(DynamicPaintSurface *surface, Scene *scen } } - if (!dynamicPaint_doStep(scene, cObject, surface, timescale, 0.0f)) return 0; - else return 1; + ret = dynamicPaint_doStep(scene, cObject, surface, timescale, 0.0f); + + return ret; } /***************************** Image Sequence Baking ******************************/ @@ -4142,8 +4551,6 @@ static int dynamicPaint_bakeImageSequence(bContext *C, DynamicPaintSurface *surf */ for (frame=surface->start_frame; frame<=surface->end_frame; frame++) { - float timescale = 1.0f; - int st; float progress = (frame - surface->start_frame) / (float)frames * 100; surface->current_frame = frame; @@ -4152,29 +4559,12 @@ static int dynamicPaint_bakeImageSequence(bContext *C, DynamicPaintSurface *surf /* Update progress bar cursor */ WM_timecursor(win, (int)progress); - printf("DynamicPaint: Baking frame %i\n", frame); - /* - * Do calculations for every substep - * Note: these have to be from previous frame - */ - 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); - - for (st = 1; st <= surface->substeps; st++) - { - float subframe = ((float) st) / (surface->substeps+1); - - if (!dynamicPaint_doStep(scene, cObject, surface, timescale, subframe)) return 0; - } - } - - if (!dynamicPaint_doStep(scene, cObject, surface, timescale, 0.0f)) return 0; + /* calculate a frame */ + scene->r.cfra = (int)frame; + ED_update_for_newframe(CTX_data_main(C), scene, win->screen, 1); + if (!dynamicPaint_calculateFrame(surface, scene, cObject, frame)) return 0; /* * Save output images diff --git a/source/blender/blenlib/BLI_kdtree.h b/source/blender/blenlib/BLI_kdtree.h index c607dae386f..12c5b4b2a5e 100644 --- a/source/blender/blenlib/BLI_kdtree.h +++ b/source/blender/blenlib/BLI_kdtree.h @@ -47,6 +47,13 @@ typedef struct KDTreeNearest { float co[3]; } KDTreeNearest; +typedef struct KDTreeNode { + struct KDTreeNode *left, *right; + float co[3], nor[3]; + int index; + short d; +} KDTreeNode; + /* Creates or free a kdtree */ KDTree* BLI_kdtree_new(int maxsize); void BLI_kdtree_free(KDTree *tree); @@ -65,5 +72,6 @@ int BLI_kdtree_find_n_nearest(KDTree *tree, int n, float *co, float *nor, KDTree /* Normal is optional, but if given will limit results to points in normal direction from co. */ /* Remember to free nearest after use! */ int BLI_kdtree_range_search(KDTree *tree, float range, float *co, float *nor, KDTreeNearest **nearest); +int BLI_kdtree_range_search_thread_safe(KDTree *tree, float range, float *co, float *nor, KDTreeNearest *nearest, int limit); #endif diff --git a/source/blender/blenlib/intern/BLI_kdtree.c b/source/blender/blenlib/intern/BLI_kdtree.c index 713bfde3417..086777afca9 100644 --- a/source/blender/blenlib/intern/BLI_kdtree.c +++ b/source/blender/blenlib/intern/BLI_kdtree.c @@ -43,13 +43,6 @@ #define SWAP(type, a, b) { type sw_ap; sw_ap=(a); (a)=(b); (b)=sw_ap; } #endif -typedef struct KDTreeNode { - struct KDTreeNode *left, *right; - float co[3], nor[3]; - int index; - short d; -} KDTreeNode; - struct KDTree { KDTreeNode *nodes; int totnode; @@ -450,3 +443,90 @@ int BLI_kdtree_range_search(KDTree *tree, float range, float *co, float *nor, KD return found; } + + +static int add_in_range_thread_safe(KDTreeNearest *ptn, int found, int *totfoundstack, int index, float dist, float *co) +{ + KDTreeNearest *to; + + if(found+1 > *totfoundstack) + return 0; + + to = ptn + found; + + to->index = index; + to->dist = sqrt(dist); + copy_v3_v3(to->co, co); + return 1; +} +int BLI_kdtree_range_search_thread_safe(KDTree *tree, float range, float *co, float *nor, KDTreeNearest *nearest, int limit) +{ + KDTreeNode *root, *node= NULL; + KDTreeNode **stack, *defaultstack[500]; + KDTreeNearest *foundstack=nearest; + float range2 = range*range, dist2; + int totstack, cur=0, found=0; + + if(!tree || !tree->root) + return 0; + + stack= defaultstack; + totstack= 500; + + root= tree->root; + + if(co[root->d] + range < root->co[root->d]) { + if(root->left) + stack[cur++]=root->left; + } + else if(co[root->d] - range > root->co[root->d]) { + if(root->right) + stack[cur++]=root->right; + } + else { + dist2 = squared_distance(root->co, co, root->nor, nor); + if(dist2 <= range2) + add_in_range_thread_safe(foundstack, found++, &limit, root->index, dist2, root->co); + + if(root->left) + stack[cur++]=root->left; + if(root->right) + stack[cur++]=root->right; + } + + while(cur--) { + node=stack[cur]; + + if(co[node->d] + range < node->co[node->d]) { + if(node->left) + stack[cur++]=node->left; + } + else if(co[node->d] - range > node->co[node->d]) { + if(node->right) + stack[cur++]=node->right; + } + else { + dist2 = squared_distance(node->co, co, node->nor, nor); + if(dist2 <= range2) + if (!add_in_range_thread_safe(foundstack, found++, &limit, node->index, dist2, node->co)) + break; + + if(node->left) + stack[cur++]=node->left; + if(node->right) + stack[cur++]=node->right; + } + + /* abort if running out of stack */ + if(cur+3 > totstack) + break; + } + + if(stack != defaultstack) + MEM_freeN(stack); + + if(found) + qsort(foundstack, found, sizeof(KDTreeNearest), range_compare); + + return found; +}
\ No newline at end of file diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index a280cae5bfe..4391cd21ad0 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -4055,10 +4055,9 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb) } if(pmd->brush) { - pmd->brush = newdataadr(fd, pmd->brush); if (pmd->brush) { + pmd->brush = newdataadr(fd, pmd->brush); pmd->brush->pmd = pmd; - pmd->brush->mat = newdataadr(fd, pmd->brush->mat); pmd->brush->psys = newdataadr(fd, pmd->brush->psys); pmd->brush->paint_ramp = newdataadr(fd, pmd->brush->paint_ramp); pmd->brush->dm = NULL; diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 94d1e8a6062..124addb9cd3 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1278,7 +1278,6 @@ static void write_modifiers(WriteData *wd, ListBase *modbase) if(pmd->brush) { writestruct(wd, DATA, "DynamicPaintBrushSettings", 1, pmd->brush); - writestruct(wd, DATA, "Material", 1, pmd->brush->mat); writestruct(wd, DATA, "ColorBand", 1, pmd->brush->paint_ramp); } } diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index bb78816e03b..85f8f93a476 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -679,7 +679,7 @@ static int modifier_can_delete(ModifierData *md) static int modifier_is_simulation(ModifierData *md) { // Physic Tab - if(ELEM6(md->type, eModifierType_Cloth, eModifierType_Collision, eModifierType_Fluidsim, eModifierType_Smoke, eModifierType_Softbody, eModifierType_Surface)) { + if(ELEM7(md->type, eModifierType_Cloth, eModifierType_Collision, eModifierType_Fluidsim, eModifierType_Smoke, eModifierType_Softbody, eModifierType_Surface, eModifierType_DynamicPaint)) { return 1; } // Particle Tab diff --git a/source/blender/makesdna/DNA_dynamicpaint_types.h b/source/blender/makesdna/DNA_dynamicpaint_types.h index d51980dbb69..d2c6e91904b 100644 --- a/source/blender/makesdna/DNA_dynamicpaint_types.h +++ b/source/blender/makesdna/DNA_dynamicpaint_types.h @@ -43,10 +43,6 @@ struct PaintSurfaceData; #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 */ - /* image_fileformat */ #define MOD_DPAINT_IMGFORMAT_PNG 0 #define MOD_DPAINT_IMGFORMAT_OPENEXR 1 @@ -101,6 +97,10 @@ typedef struct DynamicPaintSurface { } DynamicPaintSurface; +/* canvas flags */ +#define MOD_DPAINT_PREVIEW_READY (1<<0) /* if viewport preview is ready */ +#define MOD_DPAINT_BAKING (1<<1) /* surface is already baking, so it wont get updated (loop) */ + /* Canvas settings */ typedef struct DynamicPaintCanvasSettings { struct DynamicPaintModifierData *pmd; /* for fast RNA access */ diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c index 7d2eccf8e81..ba01b1f36ba 100644 --- a/source/blender/modifiers/intern/MOD_dynamicpaint.c +++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c @@ -126,6 +126,9 @@ static void foreachIDLink(ModifierData *md, Object *ob, walk(userData, ob, (ID **)&surface->brush_group); } } + if (pmd->brush) { + walk(userData, ob, (ID **)&pmd->brush->mat); + } } ModifierTypeInfo modifierType_DynamicPaint = { diff --git a/source/blender/render/intern/include/pointdensity.h b/source/blender/render/intern/include/pointdensity.h index bf697b0dcad..27907936444 100644 --- a/source/blender/render/intern/include/pointdensity.h +++ b/source/blender/render/intern/include/pointdensity.h @@ -41,6 +41,7 @@ struct Render; struct TexResult; +void cache_pointdensity(struct Render *re, struct Tex *tex); void make_pointdensities(struct Render *re); void free_pointdensities(struct Render *re); int pointdensitytex(struct Tex *tex, float *texvec, struct TexResult *texres); diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index b45528b96d9..8211c9c0f72 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -237,7 +237,7 @@ static void pointdensity_cache_object(Render *re, PointDensity *pd, Object *ob) dm->release(dm); } -static void cache_pointdensity(Render *re, Tex *tex) +void cache_pointdensity(Render *re, Tex *tex) { PointDensity *pd = tex->pd; diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index 3de9e7d2b0e..00c993bb9f8 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -148,6 +148,7 @@ struct Render *RE_NewRender(const char *name){return (struct Render*) NULL;} void RE_SwapResult(struct Render *re, struct RenderResult **rr){} void RE_BlenderFrame(struct Render *re, struct Scene *scene, int frame){} void cache_voxeldata(struct Tex *tex, int scene_frame){} +void cache_pointdensity(struct Render *re, struct Tex *tex){} /* rna */ float *give_cursor(struct Scene *scene, struct View3D *v3d){return (float *) NULL;} |