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-16 14:41:00 +0400
committerMiika Hamalainen <blender@miikah.org>2011-06-16 14:41:00 +0400
commit3de22dec26606c2c526f7193db038fa5125f9b03 (patch)
treedd308dd2061a50b0f1bc2e63b6c05716f9bcab73 /source/blender/blenkernel
parent3b41ab432badf2d4598b798e0d0c6c9ece51172b (diff)
Dynamic Paint:
Committed changes from previous weeks, biggest changes are: * Canvas can now have multiple "surfaces" that each can have specific format, type and settings. * Renewed UI to support this new system. * Aside from old "image sequence" output format, Dynamic Paint can now work on vertex level as well. Currently vertex paint and displace are supported. * Integrated vertex level painting with Point Cache. * Added viewport preview for Point Cache surfaces. Due to massive amount of changes, old Dynamic Paint saves are no longer supported. Also some features are temporarily missing or may not work properly.
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_dynamicpaint.h81
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h6
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c4
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c3850
-rw-r--r--source/blender/blenkernel/intern/particle.c6
-rw-r--r--source/blender/blenkernel/intern/pointcache.c160
6 files changed, 2121 insertions, 1986 deletions
diff --git a/source/blender/blenkernel/BKE_dynamicpaint.h b/source/blender/blenkernel/BKE_dynamicpaint.h
index b0d97e9680b..791f218d4ca 100644
--- a/source/blender/blenkernel/BKE_dynamicpaint.h
+++ b/source/blender/blenkernel/BKE_dynamicpaint.h
@@ -14,73 +14,56 @@
#ifndef BKE_DYNAMIC_PAINT_H_
#define BKE_DYNAMIC_PAINT_H_
-typedef struct FaceAdv {
- float no[3];
- float no_q[3];
-} FaceAdv;
-
-typedef struct BB2d {
- float min[2], max[2];
-} BB2d;
-
-typedef struct Vec3f {
- float v[3];
-} Vec3f;
-
+#include "DNA_dynamicpaint_types.h"
/* Actual surface point */
-typedef struct PaintSurfacePoint {
- /*
- * Paint layer data
- */
- float color[3];
- float alpha;
- float depth; /* displacement */
+typedef struct PaintSurfaceData {
+ /* surface format data */
+ void *format_data;
+ /* surface type data */
+ void *type_data;
- /*
- * Effect / moving layer data
- * ! Only generated if effects enabled !
- */
- int neighbours[8]; /* Indexes of 8 neighbouring pixels if exist */
- float neighbour_dist[8]; /* Distances to all 8 neighbouring pixels */
- float gravity_dir; /* UV space direction of gravity */
- float gravity_rate; /* Gravity strength. (Depends on surface angle.) */
+ unsigned int total_points;
+ short samples;
+} PaintSurfaceData;
+
+/* Paint type surface point */
+typedef struct PaintPoint {
/* Wet paint is handled at effect layer only
* and mixed to surface when drying */
float e_color[3];
float e_alpha;
float wetness;
- short state; /* 0 = empty or dry
+ short state; /* -1 = doesn't exist (On UV mapped image
+ * there can be points that doesn't exist on mesh surface)
+ * 0 = empty or dry
* 1 = wet paint
* 2 = new paint */
+ float color[3];
+ float alpha;
+} PaintPoint;
+/* iWave type surface point */
+typedef struct PaintIWavePoint {
- /*
- * Pixel / mesh data
- */
- int index; /* face index on domain derived mesh */
- int v1, v2, v3; /* vertex indexes */
-
- 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 */
- float realCoord[3]; /* current pixel center world-space coordinates */
- float invNorm[3]; /*current pixel world-space inverted normal. depends on smooth/flat shading */
+ float source;
+ float obstruction;
+ float height, previousHeight;
-} PaintSurfacePoint;
+ float foam;
-typedef struct PaintSurface {
-
- struct PaintSurfacePoint *point;
- int w, h, active_points;
- short pixelSamples;
-} PaintSurface;
+ float verticalDerivative;
-void dynamicPaint_Modifier_do(struct DynamicPaintModifierData *pmd, struct Scene *scene, struct Object *ob, struct DerivedMesh *dm);
+} PaintIWavePoint;
+struct DerivedMesh *dynamicPaint_Modifier_do(struct DynamicPaintModifierData *pmd, struct Scene *scene, struct Object *ob, struct DerivedMesh *dm);
+void dynamicPaint_cacheUpdateFrames(struct DynamicPaintSurface *surface);
+int dynamicPaint_resetSurface(struct DynamicPaintSurface *surface);
+int dynamicPaint_surfaceHasPreview(DynamicPaintSurface *surface);
+void dynamicPaintSurface_updateType(struct DynamicPaintSurface *surface);
+void dynamicPaintSurface_setUniqueName(DynamicPaintSurface *surface, char *basename);
void dynamicPaint_Modifier_free (struct DynamicPaintModifierData *pmd);
void dynamicPaint_Modifier_createType(struct DynamicPaintModifierData *pmd);
void dynamicPaint_Modifier_copy(struct DynamicPaintModifierData *pmd, struct DynamicPaintModifierData *tsmd);
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h
index 346368a5958..d7601b232c6 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -34,6 +34,7 @@
*/
#include "DNA_ID.h"
+#include "DNA_dynamicpaint_types.h"
#include "DNA_object_force.h"
#include "DNA_boid_types.h"
#include <stdio.h> /* for FILE */
@@ -66,6 +67,7 @@
#define PTCACHE_TYPE_CLOTH 2
#define PTCACHE_TYPE_SMOKE_DOMAIN 3
#define PTCACHE_TYPE_SMOKE_HIGHRES 4
+#define PTCACHE_TYPE_DYNAMICPAINT 5
/* high bits reserved for flags that need to be stored in file */
#define PTCACHE_TYPEFLAG_COMPRESS (1<<16)
@@ -90,6 +92,7 @@ struct PointCache;
struct Scene;
struct SmokeModifierData;
struct SoftBody;
+struct DynamicPaintModifierData;
/* temp structure for read/write */
typedef struct PTCacheData {
@@ -139,7 +142,7 @@ typedef struct PTCacheID {
/* copies point data to cache data */
int (*write_stream)(PTCacheFile *pf, void *calldata);
/* copies cache cata to point data */
- void (*read_stream)(PTCacheFile *pf, void *calldata);
+ int (*read_stream)(PTCacheFile *pf, void *calldata);
/* copies custom extradata to cache data */
void (*write_extra_data)(void *calldata, struct PTCacheMem *pm, int cfra);
@@ -255,6 +258,7 @@ void BKE_ptcache_id_from_softbody(PTCacheID *pid, struct Object *ob, struct Soft
void BKE_ptcache_id_from_particles(PTCacheID *pid, struct Object *ob, struct ParticleSystem *psys);
void BKE_ptcache_id_from_cloth(PTCacheID *pid, struct Object *ob, struct ClothModifierData *clmd);
void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeModifierData *smd);
+void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, struct Object *ob, struct DynamicPaintSurface *surface);
void BKE_ptcache_ids_from_object(struct ListBase *lb, struct Object *ob, struct Scene *scene, int duplis);
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index 72ee9b55800..bf6fb155896 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -878,7 +878,9 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us
if(useColors && mc)
cp = (unsigned char *)&mc[i * 4];
- glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
+ /* dont set shading mode to flat because
+ * normals are used to change shading */
+ glShadeModel(GL_SMOOTH);
glBegin(mf->v4?GL_QUADS:GL_TRIANGLES);
if (!drawSmooth) {
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 9e9879fcae0..79a45568ee1 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -15,29 +15,40 @@
#include "MEM_guardedalloc.h"
#include <math.h>
-#include "stdio.h"
+#include <stdio.h>
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_kdtree.h"
#include "BLI_utildefines.h"
+/* Platform independend time */
+#include "PIL_time.h"
+
+#include "BKE_animsys.h"
#include "BKE_bvhutils.h" /* bvh tree */
#include "BKE_blender.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_colortools.h"
+#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
+#include "BKE_dynamicpaint.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_modifier.h"
+#include "BKE_object.h"
#include "BKE_particle.h"
+#include "BKE_pointcache.h"
#include "BKE_report.h"
+#include "BKE_scene.h"
#include "BKE_texture.h"
+#include "DNA_anim_types.h"
#include "DNA_dynamicpaint_types.h"
+#include "DNA_group_types.h" /*GroupObject*/
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
@@ -62,9 +73,6 @@
/* uv validate */
#include "intern/MOD_util.h"
-/* Platform independend time */
-#include "PIL_time.h"
-
/* to read object material color */
#include "DNA_texture_types.h"
#include "../render/intern/include/render_types.h"
@@ -72,21 +80,15 @@
#include "DNA_material_types.h"
#include "RE_render_ext.h"
-#include "BKE_dynamicpaint.h"
-
#define DPOUTPUT_JPEG 0
#define DPOUTPUT_PNG 1
#define DPOUTPUT_OPENEXR 2
-#define DPOUTPUT_PAINT 0
-#define DPOUTPUT_WET 1
-#define DPOUTPUT_DISPLACE 2
-
struct Object;
struct Scene;
struct DerivedMesh;
-struct DynamicPaintModifierData;
+//struct DynamicPaintModifierData;
/*
* Init predefined antialias jitter data
@@ -106,78 +108,325 @@ float gaussianFactors[5] = { 0.996849f,
float gaussianTotal = 3.309425f;
/*
-* Neighbouring pixel table x and y list
+* UV Image neighbouring pixel table x and y list
*/
int neighX[8] = {1,1,0,-1,-1,-1, 0, 1};
int neighY[8] = {0,1,1, 1, 0,-1,-1,-1};
+static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *surface, float timescale, float subframe);
+static int dynamicPaint_calculateFrame(DynamicPaintSurface *surface, Scene *scene, Object *cObject, int frame);
+
+/***************************** Internal Structs ***************************/
+
+typedef struct FaceAdv {
+ float no[3];
+ float no_q[3];
+} FaceAdv;
+
+typedef struct BB2d {
+ float min[2], max[2];
+} BB2d;
+
+typedef struct Vec3f {
+ float v[3];
+} Vec3f;
+
+/* Surface data used while processing a frame */
+typedef struct PaintBakePoint {
+ float realCoord[3]; /* current pixel center world-space coordinates */
+ 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;
+
+/* 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 */
+
+
+ /* Pixel / mesh data */
+ int face_index, pixel_index; /* face index on domain derived mesh */
+ int v1, v2, v3; /* vertex indexes */
+
+ 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;
+
+/***************************** General Utils ******************************/
/*
-* Modifier call. Updates derived mesh data if baking.
+* Output error message to both ui and console
*/
-void dynamicPaint_Modifier_update(struct DynamicPaintModifierData *pmd, DerivedMesh *dm)
+static int printError(DynamicPaintCanvasSettings *canvas, char *string)
{
+ if (strlen(string)>64) string[63] = '\0';
- if (!pmd->baking) return;
+ /* Add error to canvas ui info label */
+ sprintf(canvas->error, string);
- if((pmd->type & MOD_DYNAMICPAINT_TYPE_CANVAS) && pmd->canvas) {
+ /* Print console output */
+ printf("DynamicPaint bake failed: %s\n", canvas->error);
+
+ return 0;
+}
- if (pmd->canvas->dm) pmd->canvas->dm->release(pmd->canvas->dm);
- pmd->canvas->dm = CDDM_copy(dm);
+/* Get number of surface points for cached types */
+static int dynamicPaint_surfaceNumOfPoints(DynamicPaintSurface *surface)
+{
+ if (surface->format == MOD_DPAINT_SURFACE_F_PTEX) {
+ return 0; /* not supported atm */
+ }
+ else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+ if (!surface->canvas->dm) return 0; /* invalid derived mesh */
+ return surface->canvas->dm->getNumVerts(surface->canvas->dm);
}
- else if((pmd->type & MOD_DYNAMICPAINT_TYPE_PAINT) && pmd->paint) {
+ else
+ return 0;
+}
- if (pmd->paint->dm) pmd->paint->dm->release(pmd->paint->dm);
- pmd->paint->dm = CDDM_copy(dm);
+/* checks whether surface's format/type has realtime preview */
+int dynamicPaint_surfaceHasPreview(DynamicPaintSurface *surface) {
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) return 0;
+ else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+ if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) return 0;
+ else return 1;
}
+ else return 1;
+}
+/* get currently active surface (in user interface) */
+static DynamicPaintSurface *get_activeSurface(DynamicPaintCanvasSettings *canvas)
+{
+ DynamicPaintSurface *surface = canvas->surfaces.first;
+ int i;
+
+ for(i=0; surface; surface=surface->next) {
+ if(i == canvas->active_sur)
+ return surface;
+ i++;
+ }
+ return NULL;
}
-/*
-* Free canvas data.
-*/
-static void dynamicPaint_Modifier_freeCanvas(struct DynamicPaintModifierData *pmd)
+/* set preview to first previewable surface */
+static void dynamicPaint_resetPreview(DynamicPaintCanvasSettings *canvas)
{
- if(pmd->canvas)
- {
+ DynamicPaintSurface *surface = canvas->surfaces.first;
+ int done=0;
+
+ for(; surface; surface=surface->next) {
+ if (!done && dynamicPaint_surfaceHasPreview(surface)) {
+ surface->flags |= MOD_DPAINT_PREVIEW;
+ done=1;
+ }
+ else
+ surface->flags &= ~MOD_DPAINT_PREVIEW;
+ }
+}
+
+/* set preview to first previewable surface */
+static void dynamicPaint_setPreview(DynamicPaintSurface *t_surface)
+{
+ DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
+ for(; surface; surface=surface->next) {
+ if (surface == t_surface)
+ surface->flags |= MOD_DPAINT_PREVIEW;
+ else
+ surface->flags &= ~MOD_DPAINT_PREVIEW;
+ }
+}
+
+/* change surface data to defaults on new type */
+void dynamicPaintSurface_updateType(struct DynamicPaintSurface *surface) {
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
+ surface->output_name[0]='\0';
+ surface->output_name2[0]='\0';
+ }
+ else {
+ sprintf(surface->output_name, "dp_");
+ strcpy(surface->output_name2,surface->output_name);
+ }
+
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ strcat(surface->output_name,"paintmap");
+ strcat(surface->output_name2,"wetmap");
+ }
+ else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
+ strcat(surface->output_name,"displace");
+ }
+ else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
+ strcat(surface->output_name,"weight");
+ }
+ else if (surface->type == MOD_DPAINT_SURFACE_T_IWAVE) {
+ strcat(surface->output_name,"iwave");
+ strcat(surface->output_name2,"foam");
+ }
+
+ /* update preview */
+ if (dynamicPaint_surfaceHasPreview(surface))
+ dynamicPaint_setPreview(surface);
+ else
+ dynamicPaint_resetPreview(surface->canvas);
+}
+
+static int surfaceDublicateNameExists(void *arg, const char *name)
+{
+ DynamicPaintSurface *t_surface = (DynamicPaintSurface*)arg;
+ DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
+
+ for(; surface; surface=surface->next) {
+ if (surface!=t_surface && !strcmp(name, surface->name)) return 1;
+ }
+ return 0;
+}
+
+void dynamicPaintSurface_setUniqueName(DynamicPaintSurface *surface, char *basename) {
+ char name[64];
+ strncpy(name, basename, 62); /* in case basename is surface->name use a copy */
+ BLI_uniquename_cb(surfaceDublicateNameExists, surface, name, '.', surface->name, sizeof(surface->name));
+}
+
+/***************************** Freeing data ******************************/
+
+/* Free brush data */
+static void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd)
+{
+ if(pmd->brush) {
+ if(pmd->brush->dm)
+ pmd->brush->dm->release(pmd->brush->dm);
+ pmd->brush->dm = NULL;
+
+ if(pmd->brush->paint_ramp)
+ MEM_freeN(pmd->brush->paint_ramp);
+ pmd->brush->paint_ramp = NULL;
+
+ MEM_freeN(pmd->brush);
+ pmd->brush = NULL;
+ }
+}
+
+static void dynamicPaint_freeSurfaceData(DynamicPaintSurface *surface)
+{
+ PaintSurfaceData *data = surface->data;
+ if (!data) return;
+
+ if (data->format_data) MEM_freeN(data->format_data);
+ if (data->type_data) MEM_freeN(data->type_data);
+
+ MEM_freeN(surface->data);
+ surface->data = NULL;
+}
+
+static void dynamicPaint_freeSurface(DynamicPaintSurface *surface)
+{
+ if (!surface) return;
+
+ /* point cache */
+ BKE_ptcache_free_list(&(surface->ptcaches));
+ surface->pointcache = NULL;
+
+ BLI_remlink(&(surface->canvas->surfaces), surface);
+ dynamicPaint_freeSurfaceData(surface);
+ MEM_freeN(surface);
+}
+
+/* Free canvas data */
+static void dynamicPaint_freeCanvas(DynamicPaintModifierData *pmd)
+{
+ if(pmd->canvas) {
+ /* Free surface data */
+ DynamicPaintSurface *surface = pmd->canvas->surfaces.first;
+ DynamicPaintSurface *next_surface = NULL;
+
+ while (surface) {
+ next_surface = surface->next;
+ dynamicPaint_freeSurface(surface);
+ surface = next_surface;
+ }
+
+ /* free dm copy */
if (pmd->canvas->dm)
pmd->canvas->dm->release(pmd->canvas->dm);
pmd->canvas->dm = NULL;
+
+ MEM_freeN(pmd->canvas);
+ pmd->canvas = NULL;
}
}
-/*
-* Free paint data.
-*/
-static void dynamicPaint_Modifier_freePaint(struct DynamicPaintModifierData *pmd)
+/* Free whole dp modifier */
+void dynamicPaint_Modifier_free(struct DynamicPaintModifierData *pmd)
{
- if(pmd->paint)
- {
- if(pmd->paint->dm)
- pmd->paint->dm->release(pmd->paint->dm);
- pmd->paint->dm = NULL;
-
-
- if(pmd->paint->paint_ramp)
- MEM_freeN(pmd->paint->paint_ramp);
- pmd->paint->paint_ramp = NULL;
+ if(pmd) {
+ dynamicPaint_freeCanvas(pmd);
+ dynamicPaint_freeBrush(pmd);
}
}
+
+/***************************** Initialize and reset ******************************/
+
/*
-* Free whole dp modifier.
+* Creates a new surface and adds it to the list
+* A pointer to this surface is returned
*/
-void dynamicPaint_Modifier_free(struct DynamicPaintModifierData *pmd)
+static DynamicPaintSurface *dynamicPaint_createNewSurface(DynamicPaintCanvasSettings *canvas)
{
- if(pmd)
- {
- dynamicPaint_Modifier_freeCanvas(pmd);
- dynamicPaint_Modifier_freePaint(pmd);
- }
+ DynamicPaintSurface *surface= MEM_callocN(sizeof(DynamicPaintSurface), "DynamicPaintSurface");
+ if (!surface) return NULL;
+
+ surface->canvas = canvas;
+ surface->format = MOD_DPAINT_SURFACE_F_VERTEX;
+ surface->type = MOD_DPAINT_SURFACE_T_PAINT;
+
+ /* cache */
+ surface->pointcache = BKE_ptcache_add(&(surface->ptcaches));
+ surface->pointcache->flag |= PTCACHE_DISK_CACHE;
+ surface->pointcache->step = 1;
+
+ /* Set initial values */
+ surface->flags = MOD_DPAINT_ANTIALIAS | MOD_DPAINT_MULALPHA | MOD_DPAINT_DRY_LOG | MOD_DPAINT_ACTIVE | MOD_DPAINT_PREVIEW;
+ surface->effect = 0;
+ surface->effect_ui = 1;
+
+ surface->diss_speed = 300;
+ surface->dry_speed = 300;
+ surface->disp_depth = 1.0f;
+ surface->disp_type = MOD_DPAINT_DISP_DISPLACE;
+ surface->image_fileformat = MOD_DPAINT_IMGFORMAT_PNG;
+
+ surface->image_resolution = 256;
+ surface->start_frame = 1;
+ surface->end_frame = 250;
+ 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");
+
+
+ dynamicPaintSurface_updateType(surface);
+
+ BLI_addtail(&canvas->surfaces, surface);
+
+ return surface;
}
/*
-* Initialize modifier data.
+* Initialize modifier data
*/
void dynamicPaint_Modifier_createType(struct DynamicPaintModifierData *pmd)
{
@@ -186,73 +435,48 @@ void dynamicPaint_Modifier_createType(struct DynamicPaintModifierData *pmd)
if(pmd->type & MOD_DYNAMICPAINT_TYPE_CANVAS)
{
if(pmd->canvas)
- dynamicPaint_Modifier_freeCanvas(pmd);
+ dynamicPaint_freeCanvas(pmd);
- pmd->canvas = MEM_callocN(sizeof(DynamicPaintCanvasSettings), "DynamicPaintCanvas");
+ pmd->canvas = MEM_callocN(sizeof(DynamicPaintCanvasSettings), "DynamicPaint Canvas");
pmd->canvas->pmd = pmd;
+ pmd->canvas->dm = NULL;
- pmd->canvas->flags = MOD_DPAINT_ANTIALIAS | MOD_DPAINT_MULALPHA | MOD_DPAINT_DRY_LOG;
- pmd->canvas->output = MOD_DPAINT_OUT_PAINT;
- pmd->canvas->effect = 0;
- pmd->canvas->effect_ui = 1;
-
- pmd->canvas->diss_speed = 300;
- pmd->canvas->dry_speed = 300;
- pmd->canvas->dflat_speed = 300;
-
- pmd->canvas->disp_depth = 1.0f;
- pmd->canvas->disp_type = MOD_DPAINT_DISP_DISPLACE;
- pmd->canvas->disp_format = MOD_DPAINT_DISPFOR_PNG;
-
- pmd->canvas->resolution = 256;
- pmd->canvas->start_frame = 1;
- pmd->canvas->end_frame = 100;
- pmd->canvas->substeps = 0;
-
- pmd->canvas->spread_speed = 1.0f;
- pmd->canvas->drip_speed = 1.0f;
- pmd->canvas->shrink_speed = 1.0f;
-
- sprintf(pmd->canvas->paint_output_path, "%spaintmap", "/tmp\\");
- sprintf(pmd->canvas->wet_output_path, "%swetmap", "/tmp\\");
- sprintf(pmd->canvas->displace_output_path, "%sdispmap", "/tmp\\");
+ /* Create one surface */
+ dynamicPaint_createNewSurface(pmd->canvas);
pmd->canvas->ui_info[0] = '\0';
-
- pmd->canvas->dm = NULL;
-
}
- else if(pmd->type & MOD_DYNAMICPAINT_TYPE_PAINT)
+ else if(pmd->type & MOD_DYNAMICPAINT_TYPE_BRUSH)
{
- if(pmd->paint)
- dynamicPaint_Modifier_freePaint(pmd);
+ if(pmd->brush)
+ dynamicPaint_freeBrush(pmd);
- pmd->paint = MEM_callocN(sizeof(DynamicPaintPainterSettings), "DynamicPaint Paint");
- pmd->paint->pmd = pmd;
+ pmd->brush = MEM_callocN(sizeof(DynamicPaintBrushSettings), "DynamicPaint Paint");
+ pmd->brush->pmd = pmd;
- pmd->paint->psys = NULL;
+ pmd->brush->psys = NULL;
- pmd->paint->flags = MOD_DPAINT_DO_PAINT | MOD_DPAINT_DO_WETNESS | MOD_DPAINT_DO_DISPLACE | MOD_DPAINT_ABS_ALPHA;
- pmd->paint->collision = MOD_DPAINT_COL_VOLUME;
+ pmd->brush->flags = 0;
+ pmd->brush->collision = MOD_DPAINT_COL_VOLUME;
- pmd->paint->mat = NULL;
- pmd->paint->r = 1.0f;
- pmd->paint->g = 1.0f;
- pmd->paint->b = 1.0f;
- pmd->paint->alpha = 1.0f;
- pmd->paint->wetness = 1.0f;
+ pmd->brush->mat = NULL;
+ pmd->brush->r = 1.0f;
+ pmd->brush->g = 1.0f;
+ pmd->brush->b = 1.0f;
+ pmd->brush->alpha = 1.0f;
+ pmd->brush->wetness = 1.0f;
- pmd->paint->paint_distance = 0.1f;
- pmd->paint->proximity_falloff = MOD_DPAINT_PRFALL_SHARP;
+ pmd->brush->paint_distance = 0.1f;
+ pmd->brush->proximity_falloff = MOD_DPAINT_PRFALL_SHARP;
- pmd->paint->displace_distance = 0.5f;
- pmd->paint->prox_displace_strength = 0.5f;
+ pmd->brush->displace_distance = 0.5f;
+ pmd->brush->prox_displace_strength = 0.5f;
- pmd->paint->particle_radius = 0.2;
- pmd->paint->particle_smooth = 0.05;
+ pmd->brush->particle_radius = 0.2;
+ pmd->brush->particle_smooth = 0.05;
- pmd->paint->dm = NULL;
+ pmd->brush->dm = NULL;
/*
* Paint proximity falloff colorramp.
@@ -260,14 +484,14 @@ void dynamicPaint_Modifier_createType(struct DynamicPaintModifierData *pmd)
{
CBData *ramp;
- pmd->paint->paint_ramp = add_colorband(0);
- ramp = pmd->paint->paint_ramp->data;
+ pmd->brush->paint_ramp = add_colorband(0);
+ ramp = pmd->brush->paint_ramp->data;
/* Add default smooth-falloff ramp. */
ramp[0].r = ramp[0].g = ramp[0].b = ramp[0].a = 1.0f;
ramp[0].pos = 0.0f;
ramp[1].r = ramp[1].g = ramp[1].b = ramp[1].pos = 1.0f;
ramp[1].a = 0.0f;
- pmd->paint->paint_ramp->tot = 2;
+ pmd->brush->paint_ramp->tot = 2;
}
}
}
@@ -283,7 +507,9 @@ void dynamicPaint_Modifier_copy(struct DynamicPaintModifierData *pmd, struct Dyn
if (tpmd->canvas) {
pmd->canvas->pmd = tpmd;
- tpmd->canvas->flags = pmd->canvas->flags;
+ tpmd->canvas->ui_info[0] = '\0';
+
+ /*tpmd->canvas->flags = pmd->canvas->flags;
tpmd->canvas->output = pmd->canvas->output;
tpmd->canvas->disp_type = pmd->canvas->disp_type;
tpmd->canvas->disp_format = pmd->canvas->disp_format;
@@ -308,42 +534,352 @@ void dynamicPaint_Modifier_copy(struct DynamicPaintModifierData *pmd, struct Dyn
tpmd->canvas->drip_speed = pmd->canvas->drip_speed;
tpmd->canvas->shrink_speed = pmd->canvas->shrink_speed;
- strncpy(tpmd->canvas->uvlayer_name, tpmd->canvas->uvlayer_name, 32);
+ strncpy(tpmd->canvas->uvlayer_name, tpmd->canvas->uvlayer_name, 32);*/
+
+ } else if (tpmd->brush) {
+ pmd->brush->pmd = tpmd;
+
+ tpmd->brush->flags = pmd->brush->flags;
+ tpmd->brush->collision = pmd->brush->collision;
+
+ tpmd->brush->r = pmd->brush->r;
+ tpmd->brush->g = pmd->brush->g;
+ tpmd->brush->b = pmd->brush->b;
+ tpmd->brush->alpha = pmd->brush->alpha;
+ tpmd->brush->wetness = pmd->brush->wetness;
+
+ tpmd->brush->particle_radius = pmd->brush->particle_radius;
+ tpmd->brush->particle_smooth = pmd->brush->particle_smooth;
+ tpmd->brush->paint_distance = pmd->brush->paint_distance;
+ tpmd->brush->psys = pmd->brush->psys;
+ tpmd->brush->displace_distance = pmd->brush->displace_distance;
+ tpmd->brush->prox_displace_strength = pmd->brush->prox_displace_strength;
+
+ tpmd->brush->paint_ramp = pmd->brush->paint_ramp;
+
+ tpmd->brush->proximity_falloff = pmd->brush->proximity_falloff;
+ }
+}
+
+/* allocates surface data depending on surface type */
+static void dynamicPaint_allocateSurfaceType(DynamicPaintSurface *surface)
+{
+ PaintSurfaceData *sData = surface->data;
+
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ sData->type_data = MEM_callocN(sizeof(PaintPoint)*sData->total_points, "DynamicPaintSurface Data");
+ }
+ else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
+ sData->type_data = MEM_callocN(sizeof(float)*sData->total_points, "DynamicPaintSurface DepthData");
+ }
+ else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
+ sData->type_data = MEM_callocN(sizeof(float)*sData->total_points, "DynamicPaintSurface WeightData");
+ }
+ else if (surface->type == MOD_DPAINT_SURFACE_T_IWAVE) {
+ sData->type_data = MEM_callocN(sizeof(PaintIWavePoint)*sData->total_points, "DynamicPaintSurface iWaveData");
+ }
+ else return;
+
+ if (sData->type_data == NULL) printError(surface->canvas, "Not enough 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);
+ }
+ }
+}
+
+/* (re)initialize surface data (only for point cache types)*/
+int dynamicPaint_resetSurface(DynamicPaintSurface *surface)
+{
+ int numOfPoints = dynamicPaint_surfaceNumOfPoints(surface);
+ /* dont touch image sequence types. they get handled only on bake */
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) return 1;
+
+ if (surface->data) dynamicPaint_freeSurfaceData(surface);
+ if (numOfPoints < 1) return 0;
+
+ /* allocate memory */
+ surface->data = MEM_callocN(sizeof(PaintSurfaceData), "PaintSurfaceData");
+ if (!surface->data) return 0;
+
+ /* allocate data depending on surface type and format */
+ surface->data->total_points = numOfPoints;
+ dynamicPaint_allocateSurfaceType(surface);
+ dynamicPaint_surfaceSetInitialValues(surface);
+
+ return 1;
+}
+
+/* make sure allocated surface size matches current requirements */
+static void dynamicPaint_checkSurfaceData(DynamicPaintSurface *surface)
+{
+ if (!surface->data || ((dynamicPaint_surfaceNumOfPoints(surface) != surface->data->total_points))) {
+ dynamicPaint_resetSurface(surface);
+ }
+}
+
- } else if (tpmd->paint) {
- pmd->paint->pmd = tpmd;
+/***************************** Modifier processing ******************************/
- tpmd->paint->flags = pmd->paint->flags;
- tpmd->paint->collision = pmd->paint->collision;
- tpmd->paint->r = pmd->paint->r;
- tpmd->paint->g = pmd->paint->g;
- tpmd->paint->b = pmd->paint->b;
- tpmd->paint->alpha = pmd->paint->alpha;
- tpmd->paint->wetness = pmd->paint->wetness;
+/* update cache frame range */
+void dynamicPaint_cacheUpdateFrames(DynamicPaintSurface *surface) {
+ if (surface->pointcache) {
+ surface->pointcache->startframe = surface->start_frame;
+ surface->pointcache->endframe = surface->end_frame;
+ }
+}
+
+/*
+* Updates derived mesh copy and processes dynamic paint step / caches.
+*/
+static void dynamicPaint_canvasUpdate(DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm)
+{
+ if((pmd->type & MOD_DYNAMICPAINT_TYPE_CANVAS) && pmd->canvas) {
+ DynamicPaintCanvasSettings *canvas = pmd->canvas;
+ DynamicPaintSurface *surface = canvas->surfaces.first;
+
+ /* update derived mesh copy */
+ if (canvas->dm) canvas->dm->release(canvas->dm);
+ canvas->dm = CDDM_copy(dm);
+
+ /* in case image sequence baking, stop here */
+ if (canvas->flags & MOD_DPAINT_BAKING) return;
+
+ /* loop through surfaces */
+ for (; surface; surface=surface->next) {
+ int current_frame = (int)scene->r.cfra;
+
+ /* image sequences are handled by bake operator */
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) continue;
+ if (!(surface->flags & MOD_DPAINT_ACTIVE)) continue;
+
+ /* make sure surface is valid */
+ dynamicPaint_checkSurfaceData(surface);
+
+ /* limit frame range */
+ CLAMP(current_frame, surface->start_frame, surface->end_frame);
+
+ if (current_frame != surface->current_frame || (int)scene->r.cfra == surface->start_frame) {
+ PointCache *cache = surface->pointcache;
+ PTCacheID pid;
+ surface->current_frame = current_frame;
+
+ /* read point cache */
+ BKE_ptcache_id_from_dynamicpaint(&pid, ob, surface);
+ pid.cache->startframe = surface->start_frame;
+ pid.cache->endframe = surface->end_frame;
+ BKE_ptcache_id_time(&pid, scene, scene->r.cfra, NULL, NULL, NULL);
+
+ /* reset non-baked cache at first frame */
+ if((int)scene->r.cfra == surface->start_frame && !(cache->flag & PTCACHE_BAKED))
+ {
+ cache->flag |= PTCACHE_REDO_NEEDED;
+ BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
+ cache->flag &= ~PTCACHE_REDO_NEEDED;
+ }
- tpmd->paint->particle_radius = pmd->paint->particle_radius;
- tpmd->paint->particle_smooth = pmd->paint->particle_smooth;
- tpmd->paint->paint_distance = pmd->paint->paint_distance;
- tpmd->paint->psys = pmd->paint->psys;
- tpmd->paint->displace_distance = pmd->paint->displace_distance;
- tpmd->paint->prox_displace_strength = pmd->paint->prox_displace_strength;
+ /* try to read from cache */
+ if(BKE_ptcache_read(&pid, (float)scene->r.cfra)) {
+ BKE_ptcache_validate(cache, (int)scene->r.cfra);
+ }
+ /* if read failed and we're on surface range do recalculate */
+ else if ((int)scene->r.cfra == current_frame) {
+ /* calculate surface frame */
+ dynamicPaint_calculateFrame(surface, scene, ob, current_frame);
- tpmd->paint->paint_ramp = pmd->paint->paint_ramp;
+ BKE_ptcache_validate(cache, surface->current_frame);
+ BKE_ptcache_write(&pid, surface->current_frame);
+ }
+ }
+ }
+ }
+ else if((pmd->type & MOD_DYNAMICPAINT_TYPE_BRUSH) && pmd->brush) {
- tpmd->paint->proximity_falloff = pmd->paint->proximity_falloff;
+ if (pmd->brush->dm) pmd->brush->dm->release(pmd->brush->dm);
+ pmd->brush->dm = CDDM_copy(dm);
}
}
+/*
+* Apply canvas data to the object derived mesh
+*/
+struct DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm)
+{
+ DerivedMesh *result = CDDM_copy(dm);
+
+ if((pmd->type & MOD_DYNAMICPAINT_TYPE_CANVAS) && pmd->canvas &&
+ !(pmd->canvas->flags & MOD_DPAINT_BAKING)) {
+
+ DynamicPaintSurface *surface = pmd->canvas->surfaces.first;
+ pmd->canvas->flags &= ~MOD_DPAINT_PREVIEW_READY;
+
+ /* loop through surfaces */
+ for (; surface; surface=surface->next) {
+
+ if (surface && surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ && surface->data) {
+ if (!(surface->flags & (MOD_DPAINT_ACTIVE))) continue;
+
+ /* process vertex surface previews */
+ if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+
+ /* vertex color paint */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+
+ MFace *mface = result->getFaceArray(result);
+ int numOfFaces = result->getNumFaces(result);
+ int i,j;
+ PaintPoint* pPoint = (PaintPoint*)surface->data->type_data;
+ MCol *col;
+
+ /* paint is stored on dry and wet layers, so mix final color first */
+ float *fcolor = MEM_callocN(sizeof(float)*surface->data->total_points*4, "Temp paint color");
+ for (i=0; i<surface->data->total_points; i++) {
+ 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+3] = (pPoint[i].e_alpha > pPoint[i].alpha) ? pPoint[i].e_alpha : pPoint[i].alpha;
+ }
+
+ /* viewport preview */
+ if (surface->flags & MOD_DPAINT_PREVIEW) {
+ /* Save preview results to weight layer, to be
+ * able to share same drawing methods */
+ col = result->getFaceDataArray(result, CD_WEIGHT_MCOL);
+ if (!col) col = CustomData_add_layer(&result->faceData, CD_WEIGHT_MCOL, CD_CALLOC, NULL, numOfFaces);
+
+ if (col) {
+ for (i=0; i<numOfFaces; i++) {
+ int j=0;
+ float invAlpha;
+ Material *material = give_current_material(ob, mface[i].mat_nr+1);
+
+ for (; j<((mface[i].v4)?4:3); j++) {
+ int index = (j==0)?mface[i].v1: (j==1)?mface[i].v2: (j==2)?mface[i].v3: mface[i].v4;
+ index *= 4;
+ invAlpha = 1.0f - fcolor[index+3];
+
+ /* Apply material color as base vertex color for preview */
+ col[i*4+j].a = 255;
+ if (material) {
+ col[i*4+j].r = (unsigned char)(material->b*255);
+ col[i*4+j].g = (unsigned char)(material->g*255);
+ col[i*4+j].b = (unsigned char)(material->r*255);
+ }
+ else {
+ col[i*4+j].r = 165;
+ col[i*4+j].g = 165;
+ col[i*4+j].b = 165;
+ }
+
+ /* mix surface color */
+ col[i*4+j].r = (char)(((float)col[i*4+j].r)*invAlpha + (fcolor[index+2]*255*fcolor[index+3]));
+ col[i*4+j].g = (char)(((float)col[i*4+j].g)*invAlpha + (fcolor[index+1]*255*fcolor[index+3]));
+ col[i*4+j].b = (char)(((float)col[i*4+j].b)*invAlpha + (fcolor[index]*255*fcolor[index+3]));
+ }
+ }
+ pmd->canvas->flags |= MOD_DPAINT_PREVIEW_READY;
+ }
+ }
+
+
+ /* save layer data to output layer */
+
+ /* paint layer */
+ col = CustomData_get_layer_named(&dm->faceData, CD_MCOL, surface->output_name);
+ if (col) {
+ for (i=0; i<numOfFaces; i++) {
+ int j=0;
+ for (; j<((mface[i].v4)?4:3); j++) {
+ int index = (j==0)?mface[i].v1: (j==1)?mface[i].v2: (j==2)?mface[i].v3: mface[i].v4;
+ index *= 4;
+
+ col[i*4+j].a = (char)(fcolor[index+3]*255);
+ col[i*4+j].r = (char)(fcolor[index+2]*255);
+ col[i*4+j].g = (char)(fcolor[index+1]*255);
+ col[i*4+j].b = (char)(fcolor[index]*255);
+ }
+ }
+ }
+ MEM_freeN(fcolor);
+
+ /* wet layer */
+ col = CustomData_get_layer_named(&dm->faceData, CD_MCOL, surface->output_name2);
+ if (col) {
+ for (i=0; i<numOfFaces; i++) {
+ int j=0;
+
+ for (; j<((mface[i].v4)?4:3); j++) {
+ int index = (j==0)?mface[i].v1: (j==1)?mface[i].v2: (j==2)?mface[i].v3: mface[i].v4;
+
+ col[i*4+j].a = 255;
+ col[i*4+j].r = (char)(pPoint[index].wetness*255);
+ col[i*4+j].g = (char)(pPoint[index].wetness*255);
+ col[i*4+j].b = (char)(pPoint[index].wetness*255);
+ }
+ }
+ }
+ }
+ /* displace paint */
+ 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;
+
+ for (i=0; i<surface->data->total_points; i++) {
+ normal_short_to_float_v3(normal, mvert[i].no);
+ normalize_v3(normal);
+
+ mvert[i].co[0] -= normal[0]*value[i];
+ mvert[i].co[1] -= normal[1]*value[i];
+ mvert[i].co[2] -= normal[2]*value[i];
+ }
+
+ CDDM_calc_normals(result);
+ }
+ /* vertex group paint */
+ else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
+ }
+ }
+ }
+ }
+ }
+ return result;
+}
-void dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm)
+/* Modifier call. Processes dynamic paint modifier step. */
+struct DerivedMesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm)
{
/* Update derived mesh data to modifier if baking */
- dynamicPaint_Modifier_update(pmd, dm);
+ dynamicPaint_canvasUpdate(pmd, scene, ob, dm);
+
+ /* Return output mesh */
+ return dynamicPaint_Modifier_apply(pmd, scene, ob, dm);
}
+/***************************** 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.
@@ -351,7 +887,7 @@ void dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scene *scene, Objec
* px,py : origin pixel x and y
* n_index : lookup direction index (use neighX,neighY to get final index)
*/
-static int dynamicPaint_findNeighbourPixel(DynamicPaintCanvasSettings *canvas, int px, int py, int n_index)
+static int dynamicPaint_findNeighbourPixel(DynamicPaintSurface *surface, 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
@@ -359,21 +895,19 @@ static int dynamicPaint_findNeighbourPixel(DynamicPaintCanvasSettings *canvas, i
*/
int x,y;
- PaintSurfacePoint *tPoint = NULL;
- PaintSurfacePoint *cPoint = NULL;
- PaintSurface *surface = NULL;
-
- surface = canvas->surface;
+ DynamicPaintSurfacePoint *tPoint = NULL;
+ DynamicPaintSurfacePoint *cPoint = NULL;
+ PaintSurfaceData *sData = surface->data;
x = px + neighX[n_index];
y = py + neighY[n_index];
- if (x<0 || x>=surface->w) return -1;
- if (y<0 || y>=surface->h) return -1;
+ if (x<0 || x>=surface->image_resolution) return -1;
+ if (y<0 || y>=surface->image_resolution) return -1;
- tPoint = (&surface->point[x+surface->w*y]); /* UV neighbour */
+ tPoint = &((PaintTexturePoint*)sData->format_data)[x+surface->image_resolution*y]; /* UV neighbour */
- cPoint = (&surface->point[px+surface->w*py]); /* Origin point */
+ cPoint = &((PaintTexturePoint*)sData->format_data)[px+surface->image_resolution*py]; /* Origin point */
/*
* Check if target point is on same face -> mark it as neighbour
@@ -550,254 +1084,297 @@ static int dynamicPaint_findNeighbourPixel(DynamicPaintCanvasSettings *canvas, i
}
}
}
+#endif
/*
-* Output error message to both ui and console
-*/
-static void dpError(DynamicPaintCanvasSettings *canvas, char *string)
-{
-
- if (strlen(string)>64) string[63] = '\0';
-
- /* Add error to canvas ui info label */
- sprintf(canvas->error, string);
-
- /* Print console output */
- printf("DynamicPaint bake failed: %s\n", canvas->error);
-}
-
-/*
-* Create Canvas Surface for baking
+* Create a surface for image sequence format
*/
-static int dynamicPaint_createCanvasSurface(DynamicPaintCanvasSettings *canvas)
+static int dynamicPaint_createUVSurface(DynamicPaintSurface *surface)
{
+ /* Antialias jitter point relative coords */
+ float jitter5sample[10] = {0.0f, 0.0f,
+ -0.2f, -0.4f,
+ 0.2f, 0.4f,
+ 0.4f, -0.2f,
+ -0.4f, 0.3f};
+ int yy;
+ int w,h;
+ int numOfFaces;
+ char uvname[32];
+ int active_points = 0;
- int yy;
- int w,h;
-
- /* Antialias jitter point relative coords */
- float jitter5sample[10] = {0.0f, 0.0f,
- -0.2f, -0.4f,
- 0.2f, 0.4f,
- 0.4f, -0.2f,
- -0.4f, 0.3f};
+ PaintSurfaceData *sData;
+ DynamicPaintCanvasSettings *canvas = surface->canvas;
+ DerivedMesh *dm = canvas->dm;
- DerivedMesh *dm = canvas->dm;
- int numOfFaces;
- MVert *mvert = NULL;
- MFace *mface = NULL;
- MTFace *tface = NULL;
+ PaintTexturePoint *tempPoints = NULL;
+ MVert *mvert = NULL;
+ MFace *mface = NULL;
+ MTFace *tface = NULL;
+ BB2d *faceBB = NULL;
- PaintSurface *surface = NULL;
- BB2d *faceBB = NULL;
- char uvname[32];
+ 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.");
- if (!dm) { dpError(canvas, "Canvas mesh not updated."); return 0;}
- numOfFaces = dm->getNumFaces(dm);
+ numOfFaces = dm->getNumFaces(dm);
+ mvert = dm->getVertArray(dm);
+ mface = dm->getFaceArray(dm);
+ /* get uv layer */
+ validate_layer_name(&dm->faceData, CD_MTFACE, surface->uvlayer_name, uvname);
+ tface = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, uvname);
- /* Allocate memory for surface */
- canvas->surface = (struct PaintSurface *) MEM_callocN(sizeof(struct PaintSurface), "MPCanvasSurface");
- if (canvas->surface == NULL) {dpError(canvas, "Not enough free memory."); return 0;}
+ /* Check for validity */
+ if (!tface) return printError(canvas, "No UV data on canvas.");
+ if (surface->image_resolution < 16 || surface->image_resolution > 8096) return printError(canvas, "Invalid resolution.");
- surface = canvas->surface;
- surface->point = NULL;
+ w = h = surface->image_resolution;
- mvert = dm->getVertArray(dm);
- mface = dm->getFaceArray(dm);
+ /*
+ * Start generating the surface
+ */
+ printf("DynamicPaint: Preparing UV surface of %ix%i pixels and %i faces.\n", w, h, numOfFaces);
- validate_layer_name(&dm->faceData, CD_MTFACE, canvas->uvlayer_name, uvname);
- tface = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, uvname);
+ /* Init data struct */
+ if (surface->data) dynamicPaint_freeSurfaceData(surface);
+ sData = surface->data = MEM_callocN(sizeof(PaintSurfaceData), "PaintSurfaceData");
+ if (!surface->data) return printError(canvas, "Not enough free memory.");
- /* Check for validity */
- if (!tface) {dpError(canvas, "No UV data on canvas."); return 0;}
- if (canvas->resolution < 16 || canvas->resolution > 8096) {dpError(canvas, "Invalid resolution."); return 0;}
-
- w = h = canvas->resolution;
- surface->w = w;
- surface->h = h;
+ 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.");
- /*
- * Start generating the surface
- */
- printf("DynamicPaint: Preparing canvas of %ix%i pixels and %i faces.\n", w, h, numOfFaces);
+ /*
+ * 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.");
- surface->pixelSamples = (canvas->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
- surface->point = (struct PaintSurfacePoint *) MEM_callocN(w*h*sizeof(struct PaintSurfacePoint), "PaintSurfaceData");
- if (surface->point == NULL) {dpError(canvas, "Not enough free memory."); return 0;}
+ for (yy=0; yy<numOfFaces; yy++) {
+ int numOfVert = (mface[yy].v4) ? 4 : 3;
+ int i;
- /*
- * 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) {dpError(canvas, "Not enough free memory."); return 0;}
+ VECCOPY2D(faceBB[yy].min, tface[yy].uv[0]);
+ VECCOPY2D(faceBB[yy].max, tface[yy].uv[0]);
- for (yy=0; yy<numOfFaces; yy++) {
+ 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];
- int numOfVert = (mface[yy].v4) ? 4 : 3;
- int i;
-
- VECCOPY2D(faceBB[yy].min, tface[yy].uv[0]);
- VECCOPY2D(faceBB[yy].max, tface[yy].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];
+ /*
+ * 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];
- 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];
+ /* Initialize barycentricWeights */
+ tPoint->barycentricWeights = (struct Vec3f *) malloc( sData->samples * sizeof(struct Vec3f ));
+ if (tPoint->barycentricWeights == NULL) return printError(canvas, "Not enough free memory.");
- }
- } // end face loop
+ }
+ }
- /*
- * Allocate antialias sample data (without threads due to malloc)
- * (Non threadable?)
- */
- for (yy = 0; yy < h; yy++)
+ /*
+ * 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++)
{
- int xx;
- for (xx = 0; xx < w; xx++)
- {
- int index = xx+w*yy;
- PaintSurfacePoint *cPoint = (&surface->point[index]);
+ int i, sample;
+ int index = xx+w*yy;
+ PaintTexturePoint *tPoint = (&tempPoints[index]);
- /* Initialize barycentricWeights */
- cPoint->barycentricWeights = (struct Vec3f *) malloc( surface->pixelSamples * sizeof(struct Vec3f ));
- if (cPoint->barycentricWeights == NULL) {dpError(canvas, "Not enough free memory."); return 0;}
+ short isInside = 0; /* if point is inside a uv face */
- }
- } // end pixel loop
+ float d1[2], d2[2], d3[2], point[5][2];
+ float dot00,dot01,dot02,dot11,dot12, invDenom, u,v;
- /*
- * 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++)
- {
- int i, sample;
- int index = xx+w*yy;
- PaintSurfacePoint *cPoint = (&surface->point[index]);
+ /* Init per pixel settings */
+ tPoint->face_index = -1;
+ tPoint->pixel_index = index;
- short isInside = 0; /* if point is inside a uv face */
+ /* Actual pixel center, used when collision is found */
+ point[0][0] = ((float)xx + 0.5f) / w;
+ point[0][1] = ((float)yy + 0.5f) / h;
- float d1[2], d2[2], d3[2], point[5][2];
- float dot00,dot01,dot02,dot11,dot12, invDenom, u,v;
+ /*
+ * 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;
- /*
- * Init per pixel settings
- */
- cPoint->color[0] = 0.0f;
- cPoint->color[1] = 0.0f;
- cPoint->color[2] = 0.0f;
- cPoint->alpha = 0.0f;
- cPoint->depth = 0.0f;
-
- cPoint->wetness = 0.0f;
- cPoint->e_alpha = 0.0f;
- cPoint->e_color[0] = 0.0f;
- cPoint->e_color[1] = 0.0f;
- cPoint->e_color[2] = 0.0f;
- cPoint->state = 0;
-
- cPoint->index = -1;
- cPoint->neighbour_pixel = -1;
-
- /* 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[2][0] = ((float)xx+1) / w;
+ point[2][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[3][0] = ((float)xx) / w;
+ point[3][1] = ((float)yy+1) / h;
- point[2][0] = ((float)xx+1) / w;
- point[2][1] = ((float)yy) / h;
+ point[4][0] = ((float)xx+1) / w;
+ point[4][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;
+ /* 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)
+ {
+ /* change d2 to test the other half */
+ VECSUB2D(d2, tface[i].uv[3], tface[i].uv[0]); // uv3 - uv0
- /* Loop through pixel samples, starting from middle point */
- for (sample=0; sample<5; sample++) {
-
- /* Loop through every face in the mesh */
- for (i=0; i<numOfFaces; i++) {
+ /* 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];
- /* 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;
+ invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
+ u = (dot11 * dot02 - dot01 * dot12) * invDenom;
+ v = (dot00 * dot12 - dot01 * dot02) * invDenom;
- /*
- * 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
+ if ((u > 0) && (v > 0) && (u + v < 1)) {isInside=2;} /* is inside the second half of the quad */
+ }
- 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];
+ /*
+ * If point was inside the face
+ */
+ if (isInside != 0) {
- invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
- u = (dot11 * dot02 - dot01 * dot12) * invDenom;
- v = (dot00 * dot12 - dot01 * dot02) * invDenom;
+ float uv1co[2], uv2co[2], uv3co[2], uv[2];
+ int j;
- if ((u > 0) && (v > 0) && (u + v < 1)) {isInside=1;} /* is inside a triangle */
+ /* 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]);
+ }
- /*
- * If collision wasn't found but the face is a quad
- * do another check for the second half
- */
- if ((!isInside) && mface[i].v4)
- {
+ /* 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;
- /* change d2 to test the other half */
- VECSUB2D(d2, tface[i].uv[3], tface[i].uv[0]); // uv3 - uv0
+ barycentric_weights_v2(uv1co, uv2co, uv3co, uv, tPoint->barycentricWeights[j].v);
+ }
- /* 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];
+ /* Set surface point face values */
+ tPoint->face_index = i; /* face index */
+ tPoint->quad = (isInside == 2) ? 1 : 0; /* quad or tri part*/
- invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
- u = (dot11 * dot02 - dot01 * dot12) * invDenom;
- v = (dot00 * dot12 - dot01 * dot02) * invDenom;
+ /* 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 */
+ }
+ }
- if ((u > 0) && (v > 0) && (u + v < 1)) {isInside=2;} /* is inside the second half of the quad */
- }
- /*
- * If point was inside the face
- */
- if (isInside != 0) {
+ /*
+ * 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++)
+ {
+ 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 j;
+ int i = tempPoints[ind].face_index, j;
- /* Get triagnle uvs */
- if (isInside==1) {
+ /* 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]);
@@ -809,123 +1386,79 @@ static int dynamicPaint_createCanvasSurface(DynamicPaintCanvasSettings *canvas)
}
/* Add b-weights per anti-aliasing sample */
- for (j=0; j<surface->pixelSamples; j++) {
-
- uv[0] = point[0][0] + jitter5sample[j*2] / w;
- uv[1] = point[0][1] + jitter5sample[j*2+1] / h;
+ for (j=0; j<sData->samples; j++) {
- barycentric_weights_v2(uv1co, uv2co, uv3co, uv, cPoint->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, tPoint->barycentricWeights[j].v);
}
- /* Set surface point face values */
- cPoint->index = i; /* face index */
- cPoint->quad = (isInside == 2) ? 1 : 0; /* quad or tri part*/
+ /* Set values */
+ tPoint->neighbour_pixel = ind; // face index
+ tPoint->quad = tempPoints[ind].quad; // quad or tri
/* save vertex indexes */
- cPoint->v1 = (isInside == 2) ? mface[i].v1 : mface[i].v1;
- cPoint->v2 = (isInside == 2) ? mface[i].v3 : mface[i].v2;
- cPoint->v3 = (isInside == 2) ? mface[i].v4 : mface[i].v3;
-
- sample = 5; /* make sure we exit sample loop as well */
- break;
- } // end isInside
- } // end face loop
- } // end sample
- } // end of yy loop
- } // end of xx loop
+ 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;
+ }
+ }
+ }
+ }
+ }
+ }
+ /*
+ * When base loop is over convert found neighbour indexes to real ones
+ * Also count the final number of active surface points
+ */
- /*
- * 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++)
+ #pragma omp parallel for schedule(static)
+ for (yy = 0; yy < h; yy++)
+ {
+ int xx;
+ for (xx = 0; xx < w; xx++)
{
- int xx;
- for (xx = 0; xx < w; xx++)
- {
- int index = xx+w*yy;
- PaintSurfacePoint *cPoint = (&surface->point[index]);
-
- /* If point isnt't on canvas mesh */
- if (cPoint->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 (surface->point[ind].index != -1) {
-
- float uv1co[2], uv2co[2], uv3co[2], uv[2];
- int i = surface->point[ind].index, j;
-
- /*
- * Now calculate pixel data for this pixel as it was on polygon surface
- */
- if (!surface->point[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<surface->pixelSamples; 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, cPoint->barycentricWeights[j].v);
- }
+ int index = xx+w*yy;
+ PaintTexturePoint *tPoint = (&tempPoints[index]);
- /* Set values */
- cPoint->neighbour_pixel = ind; // face index
- cPoint->quad = surface->point[ind].quad; // quad or tri
-
- /* save vertex indexes */
- cPoint->v1 = (cPoint->quad) ? mface[i].v1 : mface[i].v1;
- cPoint->v2 = (cPoint->quad) ? mface[i].v3 : mface[i].v2;
- cPoint->v3 = (cPoint->quad) ? mface[i].v4 : mface[i].v3;
+ 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++;
+ }
+ }
- u = u_max + 1; /* make sure we exit outer loop as well */
- break;
- }
+#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;
+ }
+ }
- } // end itself check
- } // end uv loop
- } // end if has index
- }
- } // end pixel loop
+#endif
- /*
- * When base loop is over convert found neighbour indexes to real ones
- * Also count the final number of active surface points
- */
- surface->active_points = 0;
+#if 0 /* Currently disabled */
+ /* If any effect enabled, create surface effect / wet layer
+ * neighbour lists. Processes possibly moving data. */
+ if (surface->effect) {
#pragma omp parallel for schedule(static)
for (yy = 0; yy < h; yy++)
@@ -933,200 +1466,178 @@ static int dynamicPaint_createCanvasSurface(DynamicPaintCanvasSettings *canvas)
int xx;
for (xx = 0; xx < w; xx++)
{
- int index = xx+w*yy;
- PaintSurfacePoint *cPoint = (&surface->point[index]);
+ int i;
+ DynamicPaintSurfacePoint *cPoint = (&surface->point[xx+w*yy]);
- if (cPoint->index == -1 && cPoint->neighbour_pixel != -1) cPoint->index = surface->point[cPoint->neighbour_pixel].index;
- if (cPoint->index != -1) surface->active_points++;
- }
- } // end pixel loop
+ /* If current point exists find all it's neighbouring pixels */
+ if (cPoint->index != -1)
+ for (i=0; i<8; i++) {
-#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;
- PaintSurfacePoint *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;
+ /* Try to find a neighbouring pixel in defined direction
+ * If not found, -1 is returned */
+ cPoint->neighbours[i] = dynamicPaint_findNeighbourPixel(canvas, xx, yy, i);
+ }
}
- } // end pixel loop
-
+ }
+ }
#endif
- /*
- * If any effect enabled, create surface effect / wet layer
- * neighbour lists. Processes possibly moving data.
- */
- if (canvas->effect) {
+ MEM_freeN(faceBB);
- #pragma omp parallel for schedule(static)
- for (yy = 0; yy < h; yy++)
- {
- int xx;
- for (xx = 0; xx < w; xx++)
- {
- int i;
- PaintSurfacePoint *cPoint = (&surface->point[xx+w*yy]);
+ /* Create final surface data without inactive points */
+ {
+ int index, cursor = 0;
+ PaintTexturePoint *tPoint = (struct PaintTexturePoint *) MEM_callocN(active_points*sizeof(struct PaintTexturePoint), "PaintTexturePoint");
- /* If current point exists find all it's neighbouring pixels */
- if (cPoint->index != -1)
- for (i=0; i<8; i++) {
+ sData->format_data = tPoint;
+ if (sData->format_data == NULL) return printError(canvas, "Not enough free memory.");
+ sData->total_points = active_points;
- /* Try to find a neighbouring pixel in defined direction
- * If not found, -1 is returned */
- cPoint->neighbours[i] = dynamicPaint_findNeighbourPixel(canvas, xx, yy, i);
- }
- }
- } // end pixel loop
- } // effect
+ for(index = 0; index < (w*h); index++) {
+ if (tempPoints[index].face_index != -1) {
+ memcpy(&tPoint[cursor], &tempPoints[index], sizeof(PaintTexturePoint));
+ cursor++;
+ }
+ }
+ MEM_freeN(tempPoints);
+ }
- MEM_freeN(faceBB);
+ /* Init surface type data */
+ dynamicPaint_allocateSurfaceType(surface);
- return 1;
+ return 1;
}
+#define DPOUTPUT_PAINT 0
+#define DPOUTPUT_WET 1
+#define DPOUTPUT_DISPLACE 2
+#define DPOUTPUT_IWAVE 3
/*
-* Free canvas surface
+* Outputs an image file from uv surface data.
*/
-static void dynamicPaint_cleanCanvasSurface(DynamicPaintCanvasSettings *canvas)
+void dynamicPaint_outputImage(DynamicPaintSurface *surface, char* filename, short format, short type)
{
+ int index;
+ ImBuf* mhImgB = NULL;
+ PaintSurfaceData *sData = surface->data;
+ PaintTexturePoint *tPoint = (PaintTexturePoint*)sData->format_data;
+ char output_file[250];
- int w,h,k;
-
- if (!canvas) return;
- if (!canvas->surface) return;
+ if (sData == NULL || sData->type_data == NULL) {printError(surface->canvas, "Image save failed: Invalid surface.");return;}
- w = canvas->surface->w;
- h = canvas->surface->h;
+ if (format == DPOUTPUT_JPEG) sprintf(output_file,"%s.jpg",filename);
+ else if (format == DPOUTPUT_OPENEXR) sprintf(output_file,"%s.exr",filename);
+ else sprintf(output_file,"%s.png",filename);
- #pragma omp parallel for schedule(static,1)
- for (k = 0; k < w*h; k++)
- {
- free(canvas->surface->point[k].barycentricWeights);
- }
+ /* Validate output file path */
+ BLI_path_abs(output_file, G.main->name);
+ BLI_make_existing_file(output_file);
- if (canvas->surface->point) MEM_freeN(canvas->surface->point);
- MEM_freeN(canvas->surface);
-}
+ /* Init image buffer */
+ mhImgB = IMB_allocImBuf(surface->image_resolution, surface->image_resolution, 32, IB_rectfloat);
+ if (mhImgB == NULL) {printError(surface->canvas, "Image save failed: Not enough free memory.");return;}
-/* A modified callback to bvh tree raycast. The tree must bust have been built using bvhtree_from_mesh_faces.
-* userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree.
-*
-* To optimize paint detection speed this doesn't calculate hit coordinates or normal.
-* If ray hit the second half of a quad, no[0] is set to 1.0f.
-*/
-static void mesh_faces_spherecast_dp(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
-{
- const BVHTreeFromMesh *data = (BVHTreeFromMesh*) userdata;
- MVert *vert = data->vert;
- MFace *face = data->face + index;
- short quad = 0;
-
- float *t0, *t1, *t2, *t3;
- t0 = vert[ face->v1 ].co;
- t1 = vert[ face->v2 ].co;
- t2 = vert[ face->v3 ].co;
- t3 = face->v4 ? vert[ face->v4].co : NULL;
+ #pragma omp parallel for schedule(static)
+ for (index = 0; index < sData->total_points; index++)
+ {
+ int pos=tPoint[index].pixel_index*4; /* image buffer position */
+
- do
- {
- float dist;
- dist = ray_tri_intersection(ray, hit->dist, t0, t1, t2);
+ /* Set values of preferred type */
+ if (type == DPOUTPUT_WET) {
+ PaintPoint *point = &((PaintPoint*)sData->type_data)[index];
+ float value = (point->wetness > 1.0f) ? 1.0f : point->wetness;
- if(dist >= 0 && dist < hit->dist)
- {
- hit->index = index;
- hit->dist = dist;
- //VECADDFAC(hit->co, ray->origin, ray->direction, dist);
- //normal_tri_v3( hit->no,t0, t1, t2);
- hit->no[0] = (quad) ? 1.0f : 0.0f;
+ mhImgB->rect_float[pos]=value;
+ mhImgB->rect_float[pos+1]=value;
+ mhImgB->rect_float[pos+2]=value;
+ mhImgB->rect_float[pos+3]=1.0f;
}
+ 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];
+ }
- t1 = t2;
- t2 = t3;
- t3 = NULL;
- quad = 1;
-
- } while(t2);
-}
+ /* use highest alpha */
+ mhImgB->rect_float[pos+3] = (point->e_alpha > point->alpha) ? point->e_alpha : point->alpha;
-/* A modified callback to bvh tree nearest point. The tree must bust have been built using bvhtree_from_mesh_faces.
-* userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree.
-*
-* To optimize paint detection speed this doesn't calculate hit normal.
-* If ray hit the second half of a quad, no[0] is set to 1.0f, else 0.0f
-*/
-static void mesh_faces_nearest_point_dp(void *userdata, int index, const float *co, BVHTreeNearest *nearest)
-{
- const BVHTreeFromMesh *data = (BVHTreeFromMesh*) userdata;
- MVert *vert = data->vert;
- MFace *face = data->face + index;
- short quad = 0;
+ /* Multiply color by alpha if enabled */
+ if (surface->flags & MOD_DPAINT_MULALPHA) {
+ mhImgB->rect_float[pos] *= mhImgB->rect_float[pos+3];
+ mhImgB->rect_float[pos+1] *= mhImgB->rect_float[pos+3];
+ mhImgB->rect_float[pos+2] *= mhImgB->rect_float[pos+3];
+ }
+ }
+ else if (type == DPOUTPUT_DISPLACE) {
+ float depth = ((float*)sData->type_data)[index];
- float *t0, *t1, *t2, *t3;
- t0 = vert[ face->v1 ].co;
- t1 = vert[ face->v2 ].co;
- t2 = vert[ face->v3 ].co;
- t3 = face->v4 ? vert[ face->v4].co : NULL;
+ if (surface->disp_type == MOD_DPAINT_DISP_DISPLACE) {
+ depth = (0.5f - depth);
+ if (depth < 0.0f) depth = 0.0f;
+ if (depth > 1.0f) depth = 1.0f;
+ }
- do
- {
- float nearest_tmp[3], dist;
- int vertex, edge;
-
- dist = nearest_point_in_tri_surface(t0, t1, t2, co, &vertex, &edge, nearest_tmp);
- if(dist < nearest->dist)
- {
- nearest->index = index;
- nearest->dist = dist;
- VECCOPY(nearest->co, nearest_tmp);
- //normal_tri_v3( nearest->no,t0, t1, t2);
- nearest->no[0] = (quad) ? 1.0f : 0.0f;
+ mhImgB->rect_float[pos]=depth;
+ mhImgB->rect_float[pos+1]=depth;
+ mhImgB->rect_float[pos+2]=depth;
+ mhImgB->rect_float[pos+3]=1.0f;
}
+ }
- t1 = t2;
- t2 = t3;
- t3 = NULL;
- quad = 1;
+ /* Save image buffer */
+ if (format == DPOUTPUT_JPEG) { /* JPEG */
+ mhImgB->ftype= JPG|95;
+ IMB_rect_from_float(mhImgB);
+ imb_savejpeg(mhImgB, output_file, IB_rectfloat);
+ }
+#ifdef WITH_OPENEXR
+ else if (format == DPOUTPUT_OPENEXR) { /* OpenEXR 32-bit float */
+ mhImgB->ftype = OPENEXR | OPENEXR_COMPRESS;
+ IMB_rect_from_float(mhImgB);
+ imb_save_openexr(mhImgB, output_file, IB_rectfloat);
+ }
+#endif
+ else { /* DPOUTPUT_PNG */
+ mhImgB->ftype= PNG|95;
+ IMB_rect_from_float(mhImgB);
+ imb_savepng(mhImgB, output_file, IB_rectfloat);
+ }
- } while(t2);
+ IMB_freeImBuf(mhImgB);
}
+/***************************** Material / Texture Sampling ******************************/
+
/*
-* Calculate inverse matrices for material related objects
-* in case texture is mapped to an object.
+* Update animated textures and calculate inverse matrices
+* for material related objects in case texture is mapped to an object.
* (obj->imat isn't auto-updated)
*/
-static void DynamicPaint_UpdateMaterial(Material *mat)
+static void dynamicPaint_updateMaterial(Material *mat, int frame)
{
MTex *mtex = NULL;
Tex *tex = NULL;
int tex_nr;
-
if (mat == NULL) return;
/*
* Loop through every material texture and check
* if they are mapped by other object
*/
-
for(tex_nr=0; tex_nr<MAX_MTEX; tex_nr++) {
/* separate tex switching */
if(mat->septex & (1<<tex_nr)) continue;
@@ -1145,41 +1656,42 @@ static void DynamicPaint_UpdateMaterial(Material *mat)
}
}
+ /* update cache if voxel data */
+ if(tex->id.us && tex->type==TEX_VOXELDATA) {
+ cache_voxeldata(tex, frame);
+ }
+ /* 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);
+ }
}
- } // end texture loop
-
+ }
}
-
-static void DynamicPaint_InitMaterialObjects(Object *paintOb, Material *ui_mat)
+/* 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)
{
-
- /*
- * Calculate inverse transformation matrix
- * for this object
- */
- invert_m4_m4(paintOb->imat, paintOb->obmat);
-
- /* Now process every material linked to this Paint object,
- * and check if any material uses object mapping. */
- if ((ui_mat == NULL) && paintOb->totcol) {
- /* If using materials that are linked to mesh,
- * check every material linked to this object*/
- int i;
-
- for (i=0; i<paintOb->totcol; i++) {
- if (paintOb->matbits[i]) DynamicPaint_UpdateMaterial(paintOb->mat[i]);
- }
+ /* Calculate inverse transformation matrix
+ * for this object */
+ invert_m4_m4(brushOb->imat, brushOb->obmat);
+
+ /* Now process every material linked to this brush object */
+ 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);
+ }
}
else {
- DynamicPaint_UpdateMaterial(ui_mat);
+ dynamicPaint_updateMaterial(ui_mat, frame);
}
-
}
-
-
-/* a modified part of shadeinput.c -> shade_input_set_uv() / shade_input_set_shade_texco() */
+/* A modified part of shadeinput.c -> shade_input_set_uv() / shade_input_set_shade_texco()
+* Used for sampling UV mapped texture color */
static void textured_face_generate_uv(float *uv, float *normal, float *hit, float *v1, float *v2, float *v3)
{
@@ -1211,7 +1723,8 @@ static void textured_face_generate_uv(float *uv, float *normal, float *hit, floa
CLAMP(uv[1], -2.0f, 1.0f);
}
-/* a modified part of shadeinput.c -> shade_input_set_uv() / shade_input_set_shade_texco() */
+/* a modified part of shadeinput.c -> shade_input_set_uv() / shade_input_set_shade_texco()
+* Used for sampling UV mapped texture color */
static void textured_face_get_uv(float *uv_co, float *normal, float *uv, int faceIndex, short quad, MTFace *tface)
{
float *uv1, *uv2, *uv3;
@@ -1239,7 +1752,7 @@ static void textured_face_get_uv(float *uv_co, float *normal, float *uv, int fac
* also see shade_input_set_shade_texco() for ORCO settings
* and shade_input_set_uv() for face uv calculation
*/
-void DynamicPaint_SampleSolidMaterial(float color[3], float *alpha, Material *mat, Object *paintOb, float xyz[3], int faceIndex, short isQuad, DerivedMesh *orcoDm)
+void dynamicPaint_sampleSolidMaterial(float color[3], float *alpha, Material *mat, Object *brushOb, float xyz[3], int faceIndex, short isQuad, DerivedMesh *orcoDm)
{
MTex *mtex = NULL;
Tex *tex = NULL;
@@ -1258,7 +1771,6 @@ void DynamicPaint_SampleSolidMaterial(float color[3], float *alpha, Material *ma
mface = orcoDm->getFaceArray(orcoDm);
v1=mface[faceIndex].v1, v2=mface[faceIndex].v2, v3=mface[faceIndex].v3;
if (isQuad) {v2=mface[faceIndex].v3; v3=mface[faceIndex].v4;}
-
normal_tri_v3( normal, mvert[v1].co, mvert[v2].co, mvert[v3].co);
/* Assign material base values */
@@ -1268,7 +1780,7 @@ void DynamicPaint_SampleSolidMaterial(float color[3], float *alpha, Material *ma
*alpha = mat->alpha;
VECCOPY(xyz_local, xyz);
- mul_m4_v3(paintOb->imat, xyz_local);
+ mul_m4_v3(brushOb->imat, xyz_local);
for(tex_nr=0; tex_nr<MAX_MTEX; tex_nr++) {
@@ -1285,12 +1797,8 @@ void DynamicPaint_SampleSolidMaterial(float color[3], float *alpha, Material *ma
/* which coords */
if(mtex->texco==TEXCO_ORCO) {
float l;
-
- /*
- * Get generated UV
- */
+ /* Get generated UV */
textured_face_generate_uv(uv, normal, xyz_local, mvert[v1].co, mvert[v2].co, mvert[v3].co);
-
l= 1.0f+uv[0]+uv[1];
/* calculate generated coordinate
@@ -1304,7 +1812,7 @@ void DynamicPaint_SampleSolidMaterial(float color[3], float *alpha, Material *ma
VECCOPY(co, xyz);
/* convert from world space to paint space */
- mul_m4_v3(paintOb->imat, co);
+ mul_m4_v3(brushOb->imat, co);
if(ob) {
mul_m4_v3(ob->imat, co);
}
@@ -1316,14 +1824,12 @@ void DynamicPaint_SampleSolidMaterial(float color[3], float *alpha, Material *ma
MTFace *tface;
/* Get UV layer */
- if(mtex->uvname[0] != 0) {
+ if(mtex->uvname[0] != 0)
tface = CustomData_get_layer_named(&orcoDm->faceData, CD_MTFACE, mtex->uvname);
- }
- else tface = DM_get_face_data_layer(orcoDm, CD_MTFACE);
-
+ else
+ tface = DM_get_face_data_layer(orcoDm, CD_MTFACE);
/* Get generated coordinates to calculate UV from */
textured_face_generate_uv(uv, normal, xyz_local, mvert[v1].co, mvert[v2].co, mvert[v3].co);
-
/* Get UV mapping coordinate */
textured_face_get_uv(co, normal, uv, faceIndex, isQuad, tface);
}
@@ -1374,10 +1880,8 @@ void DynamicPaint_SampleSolidMaterial(float color[3], float *alpha, Material *ma
/* mapping */
if(mtex->mapto & (MAP_COL)) {
float tcol[3];
-
/* stencil maps on the texture control slider, not texture intensity value */
tcol[0]=texres.tr; tcol[1]=texres.tg; tcol[2]=texres.tb;
-
if((rgbnor & TEX_RGB)==0) {
tcol[0]= mtex->r;
tcol[1]= mtex->g;
@@ -1387,7 +1891,6 @@ void DynamicPaint_SampleSolidMaterial(float color[3], float *alpha, Material *ma
texres.tin= stencilTin;
}
else texres.tin= texres.ta;
-
if(mtex->mapto & MAP_COL) {
float colfac= mtex->colfac*stencilTin;
texture_rgb_blend(color, tcol, color, texres.tin, colfac, mtex->blendtype);
@@ -1396,7 +1899,6 @@ void DynamicPaint_SampleSolidMaterial(float color[3], float *alpha, Material *ma
if(mtex->mapto & MAP_VARS) {
/* stencil maps on the texture control slider, not texture intensity value */
-
if(rgbnor & TEX_RGB) {
if(texres.talpha) texres.tin= texres.ta;
else texres.tin= (0.35*texres.tr+0.45*texres.tg+0.2*texres.tb);
@@ -1404,7 +1906,6 @@ void DynamicPaint_SampleSolidMaterial(float color[3], float *alpha, Material *ma
if(mtex->mapto & MAP_ALPHA) {
float alphafac= mtex->alphafac*stencilTin;
-
*alpha= texture_value_blend(mtex->def_var, *alpha, texres.tin, alphafac, mtex->blendtype);
if(*alpha<0.0) *alpha= 0.0;
else if(*alpha>1.0) *alpha= 1.0;
@@ -1423,9 +1924,8 @@ void DynamicPaint_SampleSolidMaterial(float color[3], float *alpha, Material *ma
*
* Keep up-to-date with new mapping settings
*/
-void DynamicPaint_SampleVolumeMaterial(float color[3], float *alpha, Material *mat, Object *paintOb, float xyz[3])
+void dynamicPaint_sampleVolumeMaterial(float color[3], float *alpha, Material *mat, Object *brushOb, float xyz[3])
{
-
int mapto_flag = MAP_DENSITY | MAP_REFLECTION_COL | MAP_TRANSMISSION_COL;
float *col = color;
@@ -1450,7 +1950,6 @@ void DynamicPaint_SampleVolumeMaterial(float color[3], float *alpha, Material *m
if(mat->mtex[tex_nr]) {
mtex= mat->mtex[tex_nr];
tex= mtex->tex;
-
if(tex==0) continue;
/* only process if this texture is mapped
@@ -1468,9 +1967,8 @@ void DynamicPaint_SampleVolumeMaterial(float color[3], float *alpha, Material *m
}
}
else if(mtex->texco==TEXCO_ORCO) {
-
{
- Object *ob= paintOb;
+ Object *ob= brushOb;
VECCOPY(co, xyz);
mul_m4_v3(ob->imat, co);
}
@@ -1479,7 +1977,6 @@ void DynamicPaint_SampleVolumeMaterial(float color[3], float *alpha, Material *m
VECCOPY(co, xyz);
}
else continue; /* Skip unsupported types */
-
if(tex->type==TEX_IMAGE) {
continue; /* not supported yet */
@@ -1502,7 +1999,6 @@ void DynamicPaint_SampleVolumeMaterial(float color[3], float *alpha, Material *m
texres.tin= (0.35*texres.tr+0.45*texres.tg+0.2*texres.tb);
rgbnor-= TEX_RGB;
}
-
/* Negate and stencil */
if(mtex->texflag & MTEX_NEGATIVE) {
if(rgbnor & TEX_RGB) {
@@ -1528,9 +2024,7 @@ void DynamicPaint_SampleVolumeMaterial(float color[3], float *alpha, Material *m
/* Map values */
if((mapto_flag & (MAP_EMISSION_COL+MAP_TRANSMISSION_COL+MAP_REFLECTION_COL)) && (mtex->mapto & (MAP_EMISSION_COL+MAP_TRANSMISSION_COL+MAP_REFLECTION_COL))) {
float tcol[3];
-
/* stencil maps on the texture control slider, not texture intensity value */
-
if((rgbnor & TEX_RGB)==0) {
tcol[0]= mtex->r;
tcol[1]= mtex->g;
@@ -1548,12 +2042,10 @@ void DynamicPaint_SampleVolumeMaterial(float color[3], float *alpha, Material *m
float colemitfac= mtex->colemitfac*stencilTin;
texture_rgb_blend(col, tcol, col, texres.tin, colemitfac, mtex->blendtype);
}
-
if((mapto_flag & MAP_REFLECTION_COL) && (mtex->mapto & MAP_REFLECTION_COL)) {
float colreflfac= mtex->colreflfac*stencilTin;
texture_rgb_blend(col, tcol, col, texres.tin, colreflfac, mtex->blendtype);
}
-
if((mapto_flag & MAP_TRANSMISSION_COL) && (mtex->mapto & MAP_TRANSMISSION_COL)) {
float coltransfac= mtex->coltransfac*stencilTin;
texture_rgb_blend(col, tcol, col, texres.tin, coltransfac, mtex->blendtype);
@@ -1582,44 +2074,38 @@ void DynamicPaint_SampleVolumeMaterial(float color[3], float *alpha, Material *m
}
/*
-* Get material (including linked textures) diffuse color and alpha in given coordinates
+* Get material diffuse color and alpha (including linked textures) in given coordinates
*
* color,paint : input/output color values
* pixelCoord : canvas pixel coordinates in global space. used if material is volumetric
-*
-* paintHit : point on paint object surface in global space. used by "surface" type materials
-* faceIndex : paintHit face index
+* paintHit : ray hit point on paint object surface in global space. used by "surface" type materials
+* faceIndex : ray hit face index
* orcoDm : orco state derived mesh of paint object
-* ui_mat : force material. if NULL, material linked to paintOb mesh is used.
+* ui_mat : force material. if NULL, material linked to mesh face is used.
*
-* *"paint object" = object to sample material color from
+* *"brush object" = object to sample material color from
*/
-void DynamicPaint_GetMaterialColor(float *color, float *alpha, Object *paintOb, float pixelCoord[3], float paintHit[3], int faceIndex, short isQuad, DerivedMesh *orcoDm, Material *ui_mat)
+void dynamicPaint_getMaterialColor(float *color, float *alpha, Object *brushOb, float pixelCoord[3], float paintHit[3], int faceIndex, short isQuad, DerivedMesh *orcoDm, Material *ui_mat)
{
-
Material *material = ui_mat;
- /*
- * Get face material
- */
+ /* Get face material */
if (material == NULL) {
MFace *mface = NULL;
mface = orcoDm->getFaceArray(orcoDm);
- material = give_current_material(paintOb, mface[faceIndex].mat_nr+1);
+ material = give_current_material(brushOb, mface[faceIndex].mat_nr+1);
if (material == NULL) return; /* No material assigned */
}
- /*
- * Sample textured material color in given position depending on material type
- */
+ /* Sample textured material color in given position depending on material type */
if (material->material_type == MA_TYPE_SURFACE) {
/* Solid material */
- DynamicPaint_SampleSolidMaterial(color, alpha, material, paintOb, paintHit, faceIndex, isQuad, orcoDm);
+ dynamicPaint_sampleSolidMaterial(color, alpha, material, brushOb, paintHit, faceIndex, isQuad, orcoDm);
}
else if (material->material_type == MA_TYPE_VOLUME) {
/* Volumetric material */
- DynamicPaint_SampleVolumeMaterial(color, alpha, material, paintOb, pixelCoord);
+ dynamicPaint_sampleVolumeMaterial(color, alpha, material, brushOb, pixelCoord);
}
else if (material->material_type == MA_TYPE_HALO) {
/* Halo type not supported */
@@ -1627,55 +2113,142 @@ void DynamicPaint_GetMaterialColor(float *color, float *alpha, Object *paintOb,
}
+/***************************** Ray / Nearest Point Utils ******************************/
+
+
+/* A modified callback to bvh tree raycast. The tree must bust have been built using bvhtree_from_mesh_faces.
+* userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree.
+*
+* To optimize brush detection speed this doesn't calculate hit coordinates or normal.
+* If ray hit the second half of a quad, no[0] is set to 1.0f.
+*/
+static void mesh_faces_spherecast_dp(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+{
+ const BVHTreeFromMesh *data = (BVHTreeFromMesh*) userdata;
+ MVert *vert = data->vert;
+ MFace *face = data->face + index;
+ short quad = 0;
+
+ float *t0, *t1, *t2, *t3;
+ t0 = vert[ face->v1 ].co;
+ t1 = vert[ face->v2 ].co;
+ t2 = vert[ face->v3 ].co;
+ t3 = face->v4 ? vert[ face->v4].co : NULL;
+
+ do
+ {
+ float dist;
+ dist = ray_tri_intersection(ray, hit->dist, t0, t1, t2);
+
+ if(dist >= 0 && dist < hit->dist)
+ {
+ hit->index = index;
+ hit->dist = dist;
+ hit->no[0] = (quad) ? 1.0f : 0.0f;
+ }
+
+ t1 = t2;
+ t2 = t3;
+ t3 = NULL;
+ quad = 1;
+
+ } while(t2);
+}
+
+/* A modified callback to bvh tree nearest point. The tree must bust have been built using bvhtree_from_mesh_faces.
+* userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree.
+*
+* To optimize brush detection speed this doesn't calculate hit normal.
+* If ray hit the second half of a quad, no[0] is set to 1.0f, else 0.0f
+*/
+static void mesh_faces_nearest_point_dp(void *userdata, int index, const float *co, BVHTreeNearest *nearest)
+{
+ const BVHTreeFromMesh *data = (BVHTreeFromMesh*) userdata;
+ MVert *vert = data->vert;
+ MFace *face = data->face + index;
+ short quad = 0;
+
+ float *t0, *t1, *t2, *t3;
+ t0 = vert[ face->v1 ].co;
+ t1 = vert[ face->v2 ].co;
+ t2 = vert[ face->v3 ].co;
+ t3 = face->v4 ? vert[ face->v4].co : NULL;
+
+ do
+ {
+ float nearest_tmp[3], dist;
+ int vertex, edge;
+
+ dist = nearest_point_in_tri_surface(t0, t1, t2, co, &vertex, &edge, nearest_tmp);
+ if(dist < nearest->dist)
+ {
+ nearest->index = index;
+ nearest->dist = dist;
+ VECCOPY(nearest->co, nearest_tmp);
+ nearest->no[0] = (quad) ? 1.0f : 0.0f;
+ }
+
+ t1 = t2;
+ t2 = t3;
+ t3 = NULL;
+ quad = 1;
+
+ } while(t2);
+}
+
+
+/***************************** Painting Calls ******************************/
+
/*
* Mix color values to canvas point.
*
-* cPoint : canvas surface point to do the changes
+* surface : canvas surface
+* index : surface point index
* paintFlags : paint object flags
* paintColor,Alpha,Wetness : to be mixed paint values
-*
* timescale : value used to adjust time dependand
* operations when using substeps
*/
-void DynamicPaint_MixPaintColors(PaintSurfacePoint *cPoint, int paintFlags, float *paintColor, float *paintAlpha, float *paintWetness, float *timescale)
+void dynamicPaint_mixPaintColors(DynamicPaintSurface *surface, int index, int paintFlags, float *paintColor, float *paintAlpha, float *paintWetness, float *timescale)
{
+ PaintPoint *pPoint = &((PaintPoint*)surface->data->type_data)[index];
/* Add paint */
if (!(paintFlags & MOD_DPAINT_ERASE)) {
float wetness;
/* If point has previous paint */
- if (cPoint->e_alpha > 0)
+ if (pPoint->e_alpha > 0)
{
/*
* Mix colors by the factor, use timescale
*/
float factor = (*paintAlpha) * (*timescale);
float invFact = 1.0f - factor;
- cPoint->e_color[0] = cPoint->e_color[0]*invFact + paintColor[0]*factor;
- cPoint->e_color[1] = cPoint->e_color[1]*invFact + paintColor[1]*factor;
- cPoint->e_color[2] = cPoint->e_color[2]*invFact + paintColor[2]*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 */
- cPoint->e_color[0] = paintColor[0];
- cPoint->e_color[1] = paintColor[1];
- cPoint->e_color[2] = paintColor[2];
+ pPoint->e_color[0] = paintColor[0];
+ pPoint->e_color[1] = paintColor[1];
+ pPoint->e_color[2] = paintColor[2];
}
/* alpha */
if (paintFlags & MOD_DPAINT_ABS_ALPHA) {
- if (cPoint->e_alpha < (*paintAlpha)) cPoint->e_alpha = (*paintAlpha);
+ if (pPoint->e_alpha < (*paintAlpha)) pPoint->e_alpha = (*paintAlpha);
}
else {
- cPoint->e_alpha += (*paintAlpha) * (*timescale);
- if (cPoint->e_alpha > 1.0f) cPoint->e_alpha = 1.0f;
+ pPoint->e_alpha += (*paintAlpha) * (*timescale);
+ if (pPoint->e_alpha > 1.0f) pPoint->e_alpha = 1.0f;
}
/* only increase wetness if it's below paint level */
- wetness = (*paintWetness) * cPoint->e_alpha;
- if (cPoint->wetness < wetness) cPoint->wetness = wetness;
+ wetness = (*paintWetness) * pPoint->e_alpha;
+ if (pPoint->wetness < wetness) pPoint->wetness = wetness;
}
/* Erase paint */
else {
@@ -1688,50 +2261,44 @@ void DynamicPaint_MixPaintColors(PaintSurfacePoint *cPoint, int paintFlags, floa
* but maintain alpha ratio
*/
if (paintFlags & MOD_DPAINT_ABS_ALPHA) {
- a_highest = (cPoint->e_alpha > cPoint->alpha) ? cPoint->e_alpha : cPoint->alpha;
+ a_highest = (pPoint->e_alpha > pPoint->alpha) ? pPoint->e_alpha : pPoint->alpha;
if (a_highest > invFact) {
a_ratio = invFact / a_highest;
- cPoint->e_alpha *= a_ratio;
- cPoint->alpha *= a_ratio;
+ pPoint->e_alpha *= a_ratio;
+ pPoint->alpha *= a_ratio;
}
}
else {
- cPoint->e_alpha -= (*paintAlpha) * (*timescale);
- if (cPoint->e_alpha < 0.0f) cPoint->e_alpha = 0.0f;
- cPoint->alpha -= (*paintAlpha) * (*timescale);
- if (cPoint->alpha < 0.0f) cPoint->alpha = 0.0f;
+ pPoint->e_alpha -= (*paintAlpha) * (*timescale);
+ if (pPoint->e_alpha < 0.0f) pPoint->e_alpha = 0.0f;
+ pPoint->alpha -= (*paintAlpha) * (*timescale);
+ if (pPoint->alpha < 0.0f) pPoint->alpha = 0.0f;
}
- wetness = (1.0f - (*paintWetness)) * cPoint->e_alpha;
- if (cPoint->wetness > wetness) cPoint->wetness = wetness;
+ wetness = (1.0f - (*paintWetness)) * pPoint->e_alpha;
+ if (pPoint->wetness > wetness) pPoint->wetness = wetness;
}
}
-
/*
-* Paint an object mesh to canvas
+* Paint a brush object mesh to the surface
*/
-static int DynamicPaint_PaintMesh(DynamicPaintCanvasSettings *canvas, Vec3f *canvasVerts, DynamicPaintPainterSettings *paint, Object *canvasOb, Object *paintOb, float timescale)
+static int dynamicPaint_paintMesh(DynamicPaintSurface *surface, PaintBakePoint *bPoint, DynamicPaintBrushSettings *brush, Object *canvasOb, Object *brushOb, float timescale)
{
DerivedMesh *dm = NULL;
MVert *mvert = NULL;
MFace *mface = NULL;
- PaintSurface *surface = canvas->surface;
+ PaintSurfaceData *sData = surface->data;
- if (!paint->dm) {
- printf("DynamicPaint: Invalid paint dm.\n");
- return 0;
- }
+ if (!brush->dm) return 0;
/* If using material color, we prepare required stuff on texture related objects first */
- if (paint->flags & MOD_DPAINT_USE_MATERIAL) DynamicPaint_InitMaterialObjects(paintOb, paint->mat);
+ if (brush->flags & MOD_DPAINT_USE_MATERIAL) dynamicPaint_initObjectMaterials(brushOb, brush->mat, surface->current_frame);
{
BVHTreeFromMesh treeData = {0};
- int yy;
- int tWidth = surface->w;
- int tHeight = surface->h;
+ int index;
int numOfVerts;
int ii;
@@ -1741,13 +2308,13 @@ static int DynamicPaint_PaintMesh(DynamicPaintCanvasSettings *canvas, Vec3f *can
* (Faster than transforming per pixel
* coordinates and normals to object space)
*/
- dm = CDDM_copy(paint->dm);
+ dm = CDDM_copy(brush->dm);
mvert = dm->getVertArray(dm);
mface = dm->getFaceArray(dm);
numOfVerts = dm->getNumVerts(dm);
for (ii=0; ii<numOfVerts; ii++) {
- mul_m4_v3(paintOb->obmat, mvert[ii].co);
+ mul_m4_v3(brushOb->obmat, mvert[ii].co);
}
/* Build a bvh tree from transformed vertices */
@@ -1755,267 +2322,248 @@ static int DynamicPaint_PaintMesh(DynamicPaintCanvasSettings *canvas, Vec3f *can
if(treeData.tree) {
#pragma omp parallel for schedule(static)
- for (yy = 0; yy < tHeight; yy++)
+ for (index = 0; index < sData->total_points; index++)
{
- int xx,i;
- for (xx = 0; xx < tWidth; xx++)
{
- PaintSurfacePoint *cPoint = (&surface->point[xx+tWidth*yy]);
- i = cPoint->index;
+ //DynamicPaintSurfacePoint *cPoint = (&surface->point[xx+tWidth*yy]);
+
+ int ss;
+ float ssFactor = 0.0f; /* super-sampling factor */
+ float depth = 0.0f; /* displace depth */
- if (i >= 0)
+ float paintColor[3] = {0.0f, 0.0f, 0.0f};
+ int numOfHits = 0;
+ float paintAlpha = 0.0f;
+
+ /* Supersampling */
+ for (ss=0; ss<1; ss++)
{
- int ss;
- float ssFactor = 0.0f; /* super-sampling factor */
- float depth = 0.0f; /* displace depth */
-
- float paintColor[3] = {0.0f, 0.0f, 0.0f};
- int numOfHits = 0;
- float paintAlpha = 0.0f;
-
- /* Supersampling */
- for (ss=0; ss<surface->pixelSamples; ss++) {
-
- float ray_start[3], ray_dir[3];
- float gaus_factor;
- BVHTreeRayHit hit;
- BVHTreeNearest nearest;
- short hit_found = 0;
- float realPos[3];
-
- /* If it's a proximity hit, store distance rate */
- float distRate = -1.0f;
-
- /* 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 (surface->pixelSamples > 1) {
- gaus_factor = gaussianFactors[ss];
- }
- else {
- gaus_factor = 1.0f;
- }
- /* Get current sample position in world coordinates */
- interp_v3_v3v3v3(realPos,
- canvasVerts[cPoint->v1].v,
- canvasVerts[cPoint->v2].v,
- canvasVerts[cPoint->v3].v, cPoint->barycentricWeights[ss].v);
- VECCOPY(ray_start, realPos);
- VECCOPY(ray_dir, cPoint->invNorm);
-
- hit.index = -1;
- hit.dist = 9999;
- nearest.index = -1;
- nearest.dist = paint->paint_distance * paint->paint_distance; /* find_nearest search uses squared distance */
-
- /* Check volume collision */
- if (paint->collision == MOD_DPAINT_COL_VOLUME || paint->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)
- {
- /* We hit a triangle, now check if collision point normal is facing the point */
+ float ray_start[3], ray_dir[3];
+ float gaus_factor;
+ BVHTreeRayHit hit;
+ BVHTreeNearest nearest;
+ short hit_found = 0;
+ /* If it's a proximity hit, store distance rate */
+ float distRate = -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;
+ /* hit data */
+ float hitCoord[3]; /* mid-sample hit coordinate */
+ int hitFace = -1; /* mid-sample hit face */
+ short hitQuad; /* mid-sample hit quad status */
- 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];
+ /* Supersampling factor */
+ /*if (surface->pixelSamples > 1) {
+ gaus_factor = gaussianFactors[ss];
+ }
+ else */{
+ gaus_factor = 1.0f;
+ }
- /*
- * If ray and hit normal are facing same direction
- * hit point is inside a closed mesh.
- */
- if (dot>=0)
- {
- /* Add factor on supersample filter */
- ssFactor += gaus_factor;
- depth += hit.dist;
- hit_found = 1;
+ /* Get current sample position in world coordinates */
+ /*interp_v3_v3v3v3(realPos,
+ canvasVerts[cPoint->v1].v,
+ canvasVerts[cPoint->v2].v,
+ canvasVerts[cPoint->v3].v, cPoint->barycentricWeights[ss].v);*/
+ VECCOPY(ray_start, bPoint[index].realCoord);
+ VECCOPY(ray_dir, bPoint[index].invNorm);
- /*
- * Mark hit info
- */
- if (hitFace == -1) {
- VECADDFAC(hitCoord, ray_start, ray_dir, hit.dist); /* Calculate final hit coordinates */
- hitQuad = quad;
- hitFace = hit.index;
- }
- }
- } // end of raycast
+ 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)
+ {
+ /* We hit a triangle, now check if collision point normal is facing the point */
+
+
+ /* 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 (quad) {v2=mface[hit.index].v3; v3=mface[hit.index].v4;}
- /* Check proximity collision */
- if ((paint->collision == MOD_DPAINT_COL_DIST || paint->collision == MOD_DPAINT_COL_VOLDIST) && (!hit_found))
+ /* 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 proxDist = -1.0f;
- float hitCo[3];
- short hQuad;
- int face;
+ /* Add factor on supersample filter */
+ ssFactor += gaus_factor;
+ depth += hit.dist;
+ hit_found = 1;
/*
- * If pure distance proximity, find the nearest point on the mesh
+ * Mark hit info
*/
- if (!(paint->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;
- }
+ if (hitFace == -1) {
+ VECADDFAC(hitCoord, ray_start, ray_dir, hit.dist); /* Calculate final hit coordinates */
+ hitQuad = quad;
+ hitFace = hit.index;
}
- else { /* else cast a ray in surface normal direction */
- negate_v3(ray_dir);
- hit.index = -1;
- hit.dist = paint->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;
- }
+ }
+ } // end of raycast
+
+ /* Check proximity collision */
+ if ((brush->collision == MOD_DPAINT_COL_DIST || brush->collision == MOD_DPAINT_COL_VOLDIST) && (!hit_found))
+ {
+ float proxDist = -1.0f;
+ float hitCo[3];
+ short hQuad;
+ int face;
+
+ /*
+ * 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;
- /* If a hit was found, calculate required values */
- if (proxDist >= 0.0f) {
- float dist_rate = proxDist / paint->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;
+ }
+ }
- /* Smooth range or color ramp */
- if (paint->proximity_falloff == MOD_DPAINT_PRFALL_SMOOTH ||
- paint->proximity_falloff == MOD_DPAINT_PRFALL_RAMP) {
+ /* If a hit was found, calculate required values */
+ if (proxDist >= 0.0f) {
+ float dist_rate = proxDist / brush->paint_distance;
- /* Limit distance to 0.0 - 1.0 */
- if (dist_rate > 1.0f) dist_rate = 1.0f;
- if (dist_rate < 0.0f) dist_rate = 0.0f;
+ /* Smooth range or color ramp */
+ if (brush->proximity_falloff == MOD_DPAINT_PRFALL_SMOOTH ||
+ brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP) {
- /* if using smooth falloff, multiply gaussian factor */
- if (paint->proximity_falloff == MOD_DPAINT_PRFALL_SMOOTH) {
- ssFactor += (1.0f - dist_rate) * gaus_factor;
- }
- else ssFactor += gaus_factor;
+ /* Limit distance to 0.0 - 1.0 */
+ if (dist_rate > 1.0f) dist_rate = 1.0f;
+ if (dist_rate < 0.0f) dist_rate = 0.0f;
- if (hitFace == -1) {
- distRate = dist_rate;
- }
+ /* if using smooth falloff, multiply gaussian factor */
+ if (brush->proximity_falloff == MOD_DPAINT_PRFALL_SMOOTH) {
+ ssFactor += (1.0f - dist_rate) * gaus_factor;
}
else ssFactor += gaus_factor;
- hit_found = 1;
-
if (hitFace == -1) {
- copy_v3_v3(hitCoord, hitCo);
- hitQuad = hQuad;
- hitFace = face;
+ distRate = dist_rate;
}
- } // proxDist
- } // end proximity check
-
- /*
- * Process color and alpha
- */
- if (hit_found)
- {
- float sampleColor[3];
- float sampleAlpha = 1.0f;
- float bandres[4];
-
- sampleColor[0] = paint->r;
- sampleColor[1] = paint->g;
- sampleColor[2] = paint->b;
-
- /* Get material+textures color on hit point if required */
- if (paint->flags & MOD_DPAINT_USE_MATERIAL) DynamicPaint_GetMaterialColor(sampleColor, &sampleAlpha, paintOb, realPos, hitCoord, hitFace, hitQuad, paint->dm, paint->mat);
-
- /* Sample colorband if required */
- if ((distRate >= 0.0f) && (paint->proximity_falloff == MOD_DPAINT_PRFALL_RAMP) && do_colorband(paint->paint_ramp, distRate, bandres)) {
- if (!(paint->flags & MOD_DPAINT_RAMP_ALPHA)) {
- sampleColor[0] = bandres[0];
- sampleColor[1] = bandres[1];
- sampleColor[2] = bandres[2];
}
- sampleAlpha *= bandres[3];
- }
+ else ssFactor += gaus_factor;
- /* Add AA sample */
- paintColor[0] += sampleColor[0];
- paintColor[1] += sampleColor[1];
- paintColor[2] += sampleColor[2];
+ hit_found = 1;
- paintAlpha += sampleAlpha;
- numOfHits++;
+ if (hitFace == -1) {
+ copy_v3_v3(hitCoord, hitCo);
+ hitQuad = hQuad;
+ hitFace = face;
+ }
+ } // proxDist
+ } // end proximity check
+
+ /*
+ * Process color and alpha
+ */
+ if (hit_found)
+ {
+ float sampleColor[3];
+ float sampleAlpha = 1.0f;
+ float bandres[4];
+
+ 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, &sampleAlpha, brushOb, bPoint[index].realCoord, 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)) {
+ if (!(brush->flags & MOD_DPAINT_RAMP_ALPHA)) {
+ sampleColor[0] = bandres[0];
+ sampleColor[1] = bandres[1];
+ sampleColor[2] = bandres[2];
+ }
+ sampleAlpha *= bandres[3];
}
- } // end supersampling
+ /* Add AA sample */
+ paintColor[0] += sampleColor[0];
+ paintColor[1] += sampleColor[1];
+ paintColor[2] += sampleColor[2];
- /* if any sample was inside paint range */
- if (ssFactor > 0.01f) {
+ paintAlpha += sampleAlpha;
+ numOfHits++;
+ }
+ } // end supersampling
- /* apply supersampling results */
- if (surface->pixelSamples > 1) {
- ssFactor /= gaussianTotal;
- }
- cPoint->state = 2;
+ /* if any sample was inside paint range */
+ if (ssFactor > 0.01f) {
- if (paint->flags & MOD_DPAINT_DO_PAINT) {
+ /* apply supersampling results */
+ /*if (surface->pixelSamples > 1) {
+ ssFactor /= gaussianTotal;
+ }*/
- float paintWetness = paint->wetness * ssFactor;
+ //cPoint->state = 2;
- /* Get final pixel color and alpha */
- paintColor[0] /= numOfHits;
- paintColor[1] /= numOfHits;
- paintColor[2] /= numOfHits;
- paintAlpha /= numOfHits;
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- /* Multiply alpha value by the ui multiplier */
- paintAlpha = paintAlpha * ssFactor * paint->alpha;
- if (paintAlpha > 1.0f) paintAlpha = 1.0f;
+ float paintWetness = brush->wetness * ssFactor;
- /*
- * Mix paint to the surface
- */
- DynamicPaint_MixPaintColors(cPoint, paint->flags, paintColor, &paintAlpha, &paintWetness, &timescale);
- }
+ /* Get final pixel color and alpha */
+ paintColor[0] /= numOfHits;
+ paintColor[1] /= numOfHits;
+ paintColor[2] /= numOfHits;
+ paintAlpha /= numOfHits;
- if (paint->flags & MOD_DPAINT_DO_DISPLACE) {
+ /* Multiply alpha value by the ui multiplier */
+ paintAlpha = paintAlpha * ssFactor * brush->alpha;
+ if (paintAlpha > 1.0f) paintAlpha = 1.0f;
- if (paint->flags & MOD_DPAINT_ERASE) {
- cPoint->depth *= (1.0f - ssFactor);
- if (cPoint->depth < 0.0f) cPoint->depth = 0.0f;
- }
- else {
- float normal_scale, tempNorm[3];
- /*
- * Calculate normal directional scale of canvas object.
- * (Displace maps work in object space)
- */
- MVert *canMvert = NULL;
- canMvert = canvas->dm->getVertArray(canvas->dm);
- normal_tri_v3( tempNorm, canMvert[cPoint->v1].co, canMvert[cPoint->v2].co, canMvert[cPoint->v3].co);
- mul_v3_v3 (tempNorm, canvasOb->size);
- normal_scale = len_v3(tempNorm);
- if (normal_scale<0.01) normal_scale = 0.01;
-
- depth /= canvas->disp_depth * surface->pixelSamples * normal_scale;
- /* do displace */
- if (cPoint->depth < depth) cPoint->depth = depth;
- }
- }
+ /*
+ * Mix paint to the surface
+ */
+ dynamicPaint_mixPaintColors(surface, index, brush->flags, paintColor, &paintAlpha, &paintWetness, &timescale);
}
- } // end i>0
- } // yy
- } // end of pixel loop
- } // end if tree exists
+ else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
+ float *value = (float*)sData->type_data;
+ if (brush->flags & MOD_DPAINT_ERASE) {
+ value[index] *= (1.0f - ssFactor);
+ if (value[index] < 0.0f) value[index] = 0.0f;
+ }
+ else {
+ depth /= bPoint[index].normal_scale;
+ /* do displace */
+ if (value[index] < depth) value[index] = depth;
+ }
+ }
+ }
+ }
+ }
+ }
/* free bhv tree */
free_bvhtree_from_mesh(&treeData);
dm->release(dm);
@@ -2025,20 +2573,16 @@ static int DynamicPaint_PaintMesh(DynamicPaintCanvasSettings *canvas, Vec3f *can
return 1;
}
-
-
/*
-* Paint a particle system to canvas
+* Paint a particle system to the surface
*/
-static int DynamicPaint_PaintParticles(DynamicPaintCanvasSettings *canvas, ParticleSystem *psys, DynamicPaintPainterSettings *paint, Object *canvasOb, float timescale)
+static int dynamicPaint_paintParticles(DynamicPaintSurface *surface, PaintBakePoint *bPoint, ParticleSystem *psys, DynamicPaintBrushSettings *brush, Object *canvasOb, float timescale)
{
- int yy;
+ int index;
ParticleSettings *part=psys->part;
ParticleData *pa = NULL;
- PaintSurface *surface = canvas->surface;
+ PaintSurfaceData *sData = surface->data;
- int tWidth = surface->w;
- int tHeight = surface->h;
KDTree *tree;
int particlesAdded = 0;
int invalidParticles = 0;
@@ -2066,785 +2610,382 @@ static int DynamicPaint_PaintParticles(DynamicPaintCanvasSettings *canvas, Parti
BLI_kdtree_insert(tree, p, pa->state.co, NULL);
particlesAdded++;
}
-
-
- if (invalidParticles) {
+ if (invalidParticles)
printf("Warning: Invalid particle(s) found!\n");
- }
/* If no suitable particles were found, exit */
if (particlesAdded < 1) {
BLI_kdtree_free(tree);
return 1;
}
-
/* balance tree */
BLI_kdtree_balance(tree);
-
/*
- * Loop through every pixel
+ * Loop through every surface point
*/
#pragma omp parallel for schedule(static)
- for (yy = 0; yy < tHeight; yy++)
+ for (index = 0; index < sData->total_points; index++)
{
- int xx;
- for (xx = 0; xx < tWidth; xx++) {
-
- int index = xx+tWidth*yy;
- PaintSurfacePoint *cPoint = (&surface->point[index]);
- int i = cPoint->index;
-
- /* If this canvas point exists */
- if (i >= 0)
- {
- int index;
- float disp_intersect = 0;
- float radius;
- float solidradius = paint->particle_radius;
- float smooth = paint->particle_smooth;
- float strength = 0.0f;
-
- /* If using per particle radius */
- if (paint->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;
-
- particles = BLI_kdtree_range_search(tree, range, cPoint->realCoord, NULL, &nearest);
- for(n=0; n<particles; n++) {
-
- /*
- * Find particle that produces highest influence
- */
- ParticleData *pa = psys->particles + nearest[n].index;
- float rad = pa->size + smooth;
- float str,smooth_range;
-
- if (nearest[n].dist > rad) continue; /* if outside range, continue to next one */
-
- if ((rad-nearest[n].dist) > disp_intersect) {
- disp_intersect = rad-nearest[n].dist;
- radius = rad;
- }
-
- /* 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);
-
- /* do smoothness if enabled */
- if (smooth) smooth_range/=smooth;
- str = 1.0f - smooth_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;
- /* if influence is greater, use this one */
- if (str > strength) strength = str;
+ particles = BLI_kdtree_range_search(tree, range, bPoint[index].realCoord, NULL, &nearest);
+ for(n=0; n<particles; n++) {
- } // end particle loop
+ /*
+ * Find particle that produces highest influence
+ */
+ ParticleData *pa = psys->particles + nearest[n].index;
+ float rad = pa->size + smooth;
+ float str,smooth_range;
- if (nearest) MEM_freeN(nearest);
+ if (nearest[n].dist > rad) continue; /* if outside range, continue to next one */
+ if ((rad-nearest[n].dist) > disp_intersect) {
+ disp_intersect = rad-nearest[n].dist;
+ radius = rad;
}
- 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 */
- index = BLI_kdtree_find_nearest(tree, cPoint->realCoord, 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;
+ /* 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);
- if (strength <= 0.0f) continue;
-
- cPoint->state = 2;
+ /* 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 (paint->flags & MOD_DPAINT_DO_PAINT) {
+ }
+ if (nearest) MEM_freeN(nearest);
- float paintAlpha = paint->alpha * strength;
- float paintWetness = paint->wetness * strength;
- float paintColor[3];
+ }
+ 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, bPoint[index].realCoord, 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;
+ }
- paintColor[0] = paint->r;
- paintColor[1] = paint->g;
- paintColor[2] = paint->b;
+ if (strength <= 0.0f) continue;
- if (paintAlpha > 1.0f) paintAlpha = 1.0f;
+ //cPoint->state = 2;
- DynamicPaint_MixPaintColors(cPoint, paint->flags, paintColor, &paintAlpha, &paintWetness, &timescale);
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- }
+ float paintAlpha = brush->alpha * strength;
+ float paintWetness = brush->wetness * strength;
+ float paintColor[3];
+ paintColor[0] = brush->r;
+ paintColor[1] = brush->g;
+ paintColor[2] = brush->b;
- if (paint->flags & MOD_DPAINT_DO_WETNESS) {
- if (cPoint->wetness < (paint->wetness*strength)) cPoint->wetness = paint->wetness*strength;
- }
+ if (paintAlpha > 1.0f) paintAlpha = 1.0f;
- if (paint->flags & MOD_DPAINT_DO_DISPLACE) {
- float sdepth, disp, normal_scale, tempNorm[3];
- MVert *canMvert = NULL;
- canMvert = canvas->dm->getVertArray(canvas->dm);
+ dynamicPaint_mixPaintColors(surface, index, brush->flags, paintColor, &paintAlpha, &paintWetness, &timescale);
- /*
- * Calculate normal directional scale of canvas object.
- * (Displace maps work in object space)
- */
- normal_tri_v3( tempNorm, canMvert[cPoint->v1].co, canMvert[cPoint->v2].co, canMvert[cPoint->v3].co);
- mul_v3_v3 (tempNorm, canvasOb->size);
- normal_scale = len_v3(tempNorm);
- if (normal_scale<0.01) normal_scale = 0.01;
+ }
+ else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
+ float sdepth;
+ float *value = (float*)sData->type_data;
- /* change falloff type to inverse square to match real displace depth */
- disp_intersect = (1.0f - sqrt(disp_intersect / radius)) * radius;
-
- /* get displace depth */
- sdepth = (radius - disp_intersect) / normal_scale;
+ /* change falloff type to inverse square to match real displace depth */
+ disp_intersect = (1.0f - sqrt(disp_intersect / radius)) * radius;
+ /* get displace depth */
+ sdepth = (radius - disp_intersect) / bPoint[index].normal_scale;
- if (sdepth<0.0f) sdepth = 0.0f;
- disp = sdepth / canvas->disp_depth;
- if (cPoint->depth < disp) cPoint->depth = disp;
- }
- }
+ if (sdepth<0.0f) sdepth = 0.0f;
+ if (value[index] < sdepth) value[index] = sdepth;
}
}
-
BLI_kdtree_free(tree);
return 1;
}
-/*
-* Prepare data required by effects for current frame.
-* Returns number of steps required
-*/
-static int DynamicPaint_Prepare_EffectStep(DynamicPaintCanvasSettings *canvas, float timescale)
-{
- double average_dist = 0.0f;
- float minimum_dist = 9999.0f;
- unsigned int count = 0;
- int steps = 1;
- PaintSurface *surface = canvas->surface;
- int yy, w=surface->w, h=surface->h;
-
- float fastest_effect, speed_factor;
-
- /*
- * Calculate current frame neighbouring pixel distances
- * and average distance between those neighbours
- */
- #pragma omp parallel for schedule(static)
- for (yy = 0; yy < h; yy++)
- {
- int xx;
- for (xx = 0; xx < w; xx++)
- {
- int i;
- PaintSurfacePoint *cPoint = (&surface->point[xx+w*yy]);
-
- if (cPoint->index != -1)
- for (i=0; i<8; i++) {
- int x,y, index;
- PaintSurfacePoint *tPoint;
-
- x = xx + neighX[i];
- y = yy + neighY[i];
-
- index = x+w*y;
- if (cPoint->neighbours[i] != -1) {
-
- tPoint = (&surface->point[index]);
- cPoint->neighbour_dist[i] = len_v3v3(cPoint->realCoord, tPoint->realCoord);
- if (cPoint->neighbour_dist[i] < minimum_dist) minimum_dist = cPoint->neighbour_dist[i];
-
- average_dist += cPoint->neighbour_dist[i];
- count++;
- }
- }
- }
-
- } // end pixel loop
-
- /*
- * Note: some other method could be better
- * Right now double precision may cause noticable error on huge
- * texture sizes (8096*8096*8 = 500 000 000 added values)
- */
- average_dist /= (double)count;
-
- /* Limit minimum distance (used to define substeps)
- * to 1/2 of the average
- */
- if (minimum_dist < (average_dist/2.0f)) minimum_dist=average_dist/2.0f;
-
- /* Get fastest effect speed and scale other effects according to it */
- fastest_effect = canvas->spread_speed;
- if (canvas->drip_speed > fastest_effect) fastest_effect = canvas->drip_speed;
- if (canvas->shrink_speed > fastest_effect) fastest_effect = canvas->shrink_speed;
-
- /* Number of steps depends on surface res, effect speed and timescale */
- speed_factor = (float)surface->w/256.0f * timescale;
- steps = (int)ceil(speed_factor*fastest_effect);
-
- speed_factor /= (float)steps;
-
- /*
- * Now calculate final per pixel speed ratio to neighbour_dist[] array
- */
- #pragma omp parallel for schedule(static)
- for (yy = 0; yy < h; yy++)
- {
- int xx;
- float dd;
- for (xx = 0; xx < w; xx++)
- {
- int i;
- PaintSurfacePoint *cPoint = (&surface->point[xx+w*yy]);
-
- if (cPoint->index != -1)
- for (i=0; i<8; i++) {
- if (cPoint->neighbours[i] != -1) {
- dd = (cPoint->neighbour_dist[i]<minimum_dist) ? minimum_dist : cPoint->neighbour_dist[i];
- cPoint->neighbour_dist[i] = minimum_dist / dd * speed_factor;
- }
- }
- }
- } // end pixel loop
-
- //printf("Average distance is %f, minimum distance is %f\n", average_dist, minimum_dist);
-
- return steps;
-}
-
-
-/*
-* Clean effect data
-*/
-static void DynamicPaint_Clean_EffectStep(DynamicPaintCanvasSettings *canvas, float timescale)
-{
- //PaintSurface *surface = canvas->surface;
-}
-
-
-/*
-* Processes active effect step.
-*/
-static void DynamicPaint_Do_EffectStep(DynamicPaintCanvasSettings *canvas, PaintSurfacePoint *prevPoint, float timescale)
-{
- PaintSurface *surface = canvas->surface;
- int yy, w=surface->w, h=surface->h;
-
- /*
- * Spread Effect
- */
- if (canvas->effect & MOD_DPAINT_EFFECT_DO_SPREAD) {
-
- #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;
- int i, validPoints = 0;
- float totalAlpha = 0.0f;
- PaintSurfacePoint *cPoint = (&surface->point[index]); /* Current source point */
- PaintSurfacePoint *ePoint; /* Effect point to shift values into */
-
- /*
- * Only reads values from the surface copy (prevPoint[]),
- * so this one is thread safe
- */
-
- /* Loop through neighbouring pixels */
- for (i=0; i<8; i++) {
- int nIndex;
- float factor, alphaAdd = 0.0f;
-
- nIndex = surface->point[index].neighbours[i];
- if (nIndex == -1) continue;
-
- /*
- * Find neighbour cells that have higher wetness
- * and expand it to this cell as well.
- */
- ePoint = (&prevPoint[nIndex]);
- validPoints++;
- totalAlpha += ePoint->e_alpha;
-
- if (ePoint->wetness <= cPoint->wetness) continue;
- factor = ePoint->wetness/8 * (ePoint->wetness - cPoint->wetness) * surface->point[index].neighbour_dist[i] * canvas->spread_speed;
-
- if (ePoint->e_alpha > cPoint->e_alpha) {
- alphaAdd = ePoint->e_alpha/8 * (ePoint->wetness*ePoint->e_alpha - cPoint->wetness*cPoint->e_alpha) * surface->point[index].neighbour_dist[i] * canvas->spread_speed;
- }
-
-
- /* If this pixel has existing paint, we have to blend it properly */
- if (cPoint->e_alpha) {
- float invFactor = 1.0f - factor;
- cPoint->e_color[0] = cPoint->e_color[0]*invFactor + ePoint->e_color[0]*factor;
- cPoint->e_color[1] = cPoint->e_color[1]*invFactor + ePoint->e_color[1]*factor;
- cPoint->e_color[2] = cPoint->e_color[2]*invFactor + ePoint->e_color[2]*factor;
-
- cPoint->e_alpha += alphaAdd;
- cPoint->wetness += factor;
- }
- else {
- /* If there is no existing paint, just replace the color */
- cPoint->e_color[0] = ePoint->e_color[0];
- cPoint->e_color[1] = ePoint->e_color[1];
- cPoint->e_color[2] = ePoint->e_color[2];
-
- cPoint->e_alpha += alphaAdd;
- cPoint->wetness += factor;
- }
-
- if (cPoint->e_alpha > 1.0f) cPoint->e_alpha = 1.0f;
- }
-
- /* For antialiasing sake, don't let alpha go much higher than average alpha of neighbours */
- if (validPoints && (cPoint->e_alpha > (totalAlpha/validPoints+0.25f))) {
- cPoint->e_alpha = (totalAlpha/validPoints+0.25f);
- if (cPoint->e_alpha>1.0f) cPoint->e_alpha = 1.0f;
- }
- }
- } // end pixel loop
- } // end spread effect
-
-
- /*
- * Drip Effect
- */
- if (canvas->effect & MOD_DPAINT_EFFECT_DO_DRIP)
- {
- memcpy(prevPoint, surface->point, surface->w*surface->h*sizeof(struct PaintSurfacePoint));
-
- //#pragma omp parallel for schedule(static)
- for (yy = 1; yy < h-1; yy++)
- {
- int xx;
- for (xx = 1; xx < w-1; xx++)
- {
- int index = xx+w*yy;
- float factor = 0.0f, drip_strength = 0.0f;
- PaintSurfacePoint *cPoint = (&prevPoint[index]); /* Current source point to read */
- PaintSurfacePoint *dPoint = (&surface->point[index]); /* Current source point to write */
- PaintSurfacePoint *ePoint; /* Effect point to shift values into */
- PaintSurfacePoint *ePoint2; /* Effect point to shift values into */
- int nIndex;
-
- /*
- * Because the neighbour pixels go in 45 degree (pi/4) slices
- * get drip factor in that range
- */
- float dirMod = fmod(cPoint->gravity_dir,0.785398163);
- float stFac=dirMod/0.785398163;
- float facTotal;
- int neighPixel,neighPixel2;
-
- /* Skip if wetness is too low */
- drip_strength = cPoint->wetness - 0.1f;
- if (drip_strength < 0) continue;
-
-
- /* Get first neighpixel index for neighbours[] array */
- neighPixel = (int)floor(cPoint->gravity_dir/6.2831853f * 8.0f);
-
- if (neighPixel > 7) neighPixel = 7; /* Shouldn't happen but just in case */
- if (neighPixel < 0) neighPixel = 0;
-
- /* Make sure the neighbour exists */
- nIndex = surface->point[index].neighbours[neighPixel];
- if (nIndex == -1) continue;
- ePoint = (&surface->point[nIndex]);
+/***************************** Dynamic Paint Step / Baking ******************************/
- /*
- * Second neighbouring point
- */
- neighPixel2 = neighPixel + 1;
- if (neighPixel2 > 7) neighPixel2 = 0;
-
- /* Make sure the neighbour exists */
- nIndex = surface->point[index].neighbours[neighPixel2];
- if (nIndex == -1) continue;
- ePoint2 = (&surface->point[nIndex]);
-
-
- /* Do some adjustments to dripping speed */
- factor = 0.3 * canvas->drip_speed;
- if (drip_strength < 2.5f) factor *= drip_strength;
-
- /* Add values to the pixel below -> drip */
- ePoint->e_color[0] = cPoint->e_color[0];
- ePoint->e_color[1] = cPoint->e_color[1];
- ePoint->e_color[2] = cPoint->e_color[2];
-
- ePoint->e_alpha += cPoint->e_alpha * factor * surface->point[index].neighbour_dist[neighPixel] * (1.0f - stFac);
- ePoint->wetness += cPoint->wetness * factor * surface->point[index].neighbour_dist[neighPixel] * (1.0f - stFac);
-
- if (stFac > 0.0f) {
- ePoint2->e_color[0] = cPoint->e_color[0];
- ePoint2->e_color[1] = cPoint->e_color[1];
- ePoint2->e_color[2] = cPoint->e_color[2];
- }
+/* Prepare for surface step by creating PaintBakePoint data */
+static int dynamicPaint_prepareSurfaceStep(DynamicPaintSurface *surface, PaintBakePoint *bPoint, Object *ob, DerivedMesh *dm, float timescale) {
+ PaintSurfaceData *sData = surface->data;
- ePoint2->e_alpha += cPoint->e_alpha * factor * surface->point[index].neighbour_dist[neighPixel2] * stFac;
- ePoint2->wetness += cPoint->wetness * factor * surface->point[index].neighbour_dist[neighPixel2] * stFac;
+ MVert *mvert = dm->getVertArray(dm);
+ MFace *mface = dm->getFaceArray(dm);
+ //MTFace *tface = DM_get_face_data_layer(dm, CD_MTFACE);
- //dPoint->e_alpha -= cPoint->e_alpha * factor;
- facTotal = surface->point[index].neighbour_dist[neighPixel] * (1.0f - stFac) + surface->point[index].neighbour_dist[neighPixel2] * stFac;
- dPoint->wetness -= cPoint->wetness * factor * facTotal;
-
- }
- } // end pixel loop
-
- /* Keep wetness values within acceptable range */
- #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;
-
- PaintSurfacePoint *cPoint = (&surface->point[index]);
-
- if (cPoint->e_alpha > 1.0f) cPoint->e_alpha=1.0f;
- if (cPoint->wetness > 3.5f) cPoint->wetness=3.5f;
-
- if (cPoint->e_alpha < 0.0f) cPoint->e_alpha=0.0f;
- if (cPoint->wetness < 0.0f) cPoint->wetness=0.0f;
-
- }
- } // end pixel loop
- } // end dripping effect
-
-
-
- /*
- * Shrink Effect
- */
- if (canvas->effect & MOD_DPAINT_EFFECT_DO_SHRINK) {
-
- #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;
- int i, validPoints = 0;
- float totalAlpha = 0.0f;
- PaintSurfacePoint *cPoint = (&surface->point[index]); /* Current source point */
- PaintSurfacePoint *ePoint; /* Effect point to shift values into */
-
- /* Loop through neighbouring pixels */
- for (i=0; i<8; i++) {
- int nIndex;
- float factor, e_factor, w_factor;
-
- nIndex = surface->point[index].neighbours[i];
-
- if (nIndex == -1) continue;
-
- /*
- * Find neighbouring cells that have lower alpha
- * and decrease this point alpha towards that level.
- */
- ePoint = (&prevPoint[nIndex]);
- validPoints++;
- totalAlpha += ePoint->e_alpha;
-
- if (cPoint->alpha <= 0.0f && cPoint->e_alpha <= 0.0f && cPoint->wetness <= 0.0f) continue;
- factor = (1.0f - ePoint->alpha)/8 * (cPoint->alpha - ePoint->alpha) * surface->point[index].neighbour_dist[i] * canvas->shrink_speed;
- if (factor < 0.0f) factor = 0.0f;
-
- e_factor = (1.0f - ePoint->e_alpha)/8 * (cPoint->e_alpha - ePoint->e_alpha) * surface->point[index].neighbour_dist[i] * canvas->shrink_speed;
- if (e_factor < 0.0f) e_factor = 0.0f;
-
- w_factor = (1.0f - ePoint->wetness)/8 * (cPoint->wetness - ePoint->wetness) * surface->point[index].neighbour_dist[i] * canvas->shrink_speed;
- if (w_factor < 0.0f) w_factor = 0.0f;
-
-
- if (factor) {
- cPoint->alpha -= factor;
- if (cPoint->alpha < 0.0f) cPoint->alpha = 0.0f;
- cPoint->wetness -= factor;
-
- }
- else {
- cPoint->e_alpha -= e_factor;
- if (cPoint->e_alpha < 0.0f) cPoint->e_alpha = 0.0f;
- cPoint->wetness -= w_factor;
- if (cPoint->wetness < 0.0f) cPoint->wetness = 0.0f;
- }
- }
- }
- } // end pixel loop
- } // end spread effect
-}
-
-
-
-/*
-* Do Dynamic Paint Step. Paints scene paint objects of current frame to canvas.
-*/
-static int DynamicPaint_DoStep(Scene *scene, Object *ob, DynamicPaintModifierData *pmd, float timescale)
-{
- DynamicPaintCanvasSettings *canvas = pmd->canvas;
- PaintSurface *surface = canvas->surface;
- Base *base = NULL;
- MVert *mvert = NULL;
- MFace *mface = NULL;
- MTFace *tface = NULL;
- DerivedMesh *dm = canvas->dm;
-
- int w, h;
- int yy;
-
- int canvasNumOfVerts;
- Vec3f *canvasVerts = NULL;
- int canvasNumOfFaces;
+ int index;
FaceAdv *canvasInvNormals = NULL;
+ Vec3f *canvasVerts = NULL;
- if (!dm) {
- dpError(canvas, "Invalid canvas mesh.");
- return 0;
- }
-
- mvert = dm->getVertArray(dm);
- mface = dm->getFaceArray(dm);
- tface = DM_get_face_data_layer(dm, CD_MTFACE);
- canvasNumOfFaces = dm->getNumFaces(dm);
-
- w = canvas->surface->w;
- h = canvas->surface->h;
+ int canvasNumOfVerts = dm->getNumVerts(dm);
+ int canvasNumOfFaces = dm->getNumFaces(dm);
/*
* Make a transformed copy of canvas derived mesh vertices to avoid recalculation.
*/
- canvasNumOfVerts = dm->getNumVerts(dm);
- canvasVerts = (struct Vec3f *) MEM_mallocN(canvasNumOfVerts*sizeof(struct Vec3f), "Dynamic Paint Transformed canvas");
- if (canvasVerts == NULL) {dpError(canvas, "Not enough free memory."); return 0;}
+ canvasVerts = (struct Vec3f *) MEM_mallocN(canvasNumOfVerts*sizeof(struct Vec3f), "Dynamic Paint transformed canvas verts");
+ if (canvasVerts == NULL) return 0;
#pragma omp parallel for schedule(static)
- for (yy=0; yy<canvasNumOfVerts; yy++) {
- VECCOPY(canvasVerts[yy].v, mvert[yy].co);
- /* Multiply coordinates by canvas matrix */
- mul_m4_v3(ob->obmat, canvasVerts[yy].v);
+ 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);
}
-
/*
- * Calculate temp per face normals using transformed coordinates.
+ * 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) {dpError(canvas, "Not enough free memory."); return 0;}
-
+ if (canvasInvNormals == NULL) return 0;
#pragma omp parallel for schedule(static)
- for (yy=0; yy<canvasNumOfFaces; yy++) {
-
- if (mface[yy].flag & ME_SMOOTH) continue; /* Only calculate flat faces */
- /*
- * Transformed normal
- */
- normal_tri_v3( canvasInvNormals[yy].no, canvasVerts[mface[yy].v3].v, canvasVerts[mface[yy].v2].v, canvasVerts[mface[yy].v1].v);
- if (mface[yy].v4) normal_tri_v3( canvasInvNormals[yy].no_q, canvasVerts[mface[yy].v4].v, canvasVerts[mface[yy].v3].v, canvasVerts[mface[yy].v1].v);
+ 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);
}
-
/*
- * Prepare each pixel for a new step
+ * Prepare each surface point for a new step
*/
#pragma omp parallel for schedule(static)
- for (yy = 0; yy < h; yy++)
+ for (index=0; index<sData->total_points; index++)
{
- int xx;
- float n1[3], n2[3], n3[3];
- for (xx = 0; xx < w; xx++)
- {
- int i,index = xx+w*yy;
- short quad;
-
- i = canvas->surface->point[index].index;
- quad = canvas->surface->point[index].quad;
-
- /* only continue if current pixel has 3D coordinates */
- if (i >= 0)
- {
- PaintSurfacePoint *cPoint = (&canvas->surface->point[index]);
-
- /*
- * Do dissolve / drying / flatten
- */
- if (cPoint->wetness > 0.0f) {
-
- /* Every drying step Blends wet paint to the background. */
- float invAlpha = 1.0f - cPoint->e_alpha;
- cPoint->color[0] = cPoint->color[0]*invAlpha + cPoint->e_color[0]*cPoint->e_alpha;
- cPoint->color[1] = cPoint->color[1]*invAlpha + cPoint->e_color[1]*cPoint->e_alpha;
- cPoint->color[2] = cPoint->color[2]*invAlpha + cPoint->e_color[2]*cPoint->e_alpha;
-
- cPoint->state = 1;
-
- /* only increase alpha if wet paint has higher */
- if (cPoint->e_alpha > cPoint->alpha) cPoint->alpha = cPoint->e_alpha;
-
- /* Now dry it ;o */
- if (canvas->flags & MOD_DPAINT_DRY_LOG) cPoint->wetness *= 1.0f - (1.0 / (canvas->dry_speed/timescale));
- else cPoint->wetness -= 1.0f/canvas->dry_speed*timescale;
- }
+ /* Do drying dissolve effects */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ PaintPoint *pPoint = &((PaintPoint*)sData->type_data)[index];
+ /* drying */
+ if (pPoint->wetness > 0.0f) {
+ /* for every drying step blend wet paint to the background */
+ float invAlpha = 1.0f - pPoint->e_alpha;
+ pPoint->color[0] = pPoint->color[0]*invAlpha + pPoint->e_color[0]*pPoint->e_alpha;
+ pPoint->color[1] = pPoint->color[1]*invAlpha + pPoint->e_color[1]*pPoint->e_alpha;
+ pPoint->color[2] = pPoint->color[2]*invAlpha + pPoint->e_color[2]*pPoint->e_alpha;
+ pPoint->state = 1;
+
+ /* only increase alpha if wet paint has higher */
+ if (pPoint->e_alpha > pPoint->alpha) pPoint->alpha = pPoint->e_alpha;
+
+ /* now dry it ;o */
+ if (surface->flags & MOD_DPAINT_DRY_LOG) pPoint->wetness *= 1.0f - (1.0 / (surface->dry_speed/timescale));
+ else pPoint->wetness -= 1.0f/surface->dry_speed*timescale;
+ }
+ /* If effect layer is completely dry, make sure it's marked empty */
+ if (pPoint->wetness <= 0.0f) {
+ pPoint->wetness = 0.0f;
+ pPoint->e_alpha = 0.0f;
+ pPoint->state = 0;
+ }
- /* If effect layer is completely dry, make sure it's marked empty */
- if (cPoint->wetness <= 0.0f) {
- cPoint->wetness = 0.0f;
- cPoint->e_alpha = 0.0f;
- cPoint->state = 0;
- }
+ if (surface->flags & MOD_DPAINT_DISSOLVE) {
- if (canvas->flags & (MOD_DPAINT_DISSOLVE)) {
+ pPoint->alpha -= 1.0f/surface->diss_speed*timescale;
+ if (pPoint->alpha < 0.0f) pPoint->alpha = 0.0f;
- cPoint->alpha -= 1.0f/canvas->diss_speed*timescale;
- if (cPoint->alpha < 0.0f) cPoint->alpha = 0.0f;
+ pPoint->e_alpha -= 1.0f/surface->diss_speed*timescale;
+ if (pPoint->e_alpha < 0.0f) pPoint->e_alpha = 0.0f;
+ }
+ }
+ else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE &&
+ surface->flags & MOD_DPAINT_DISSOLVE) {
+ float *point = &((float*)sData->type_data)[index];
- cPoint->e_alpha -= 1.0f/canvas->diss_speed*timescale;
- if (cPoint->e_alpha < 0.0f) cPoint->e_alpha = 0.0f;
- }
+ *point *= 1.0f - (1.0 / (surface->diss_speed/timescale));
+ }
- if (canvas->flags & (MOD_DPAINT_FLATTEN)) {
+ /*
+ * Calculate current 3D-position of each surface pixel
+ */
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
+ float n1[3], n2[3], n3[3];
+ PaintTexturePoint *tPoint = &((PaintTexturePoint*)sData->format_data)[index];
+
+ interp_v3_v3v3v3( bPoint[index].realCoord,
+ canvasVerts[tPoint->v1].v,
+ canvasVerts[tPoint->v2].v,
+ canvasVerts[tPoint->v3].v, tPoint->barycentricWeights[0].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( bPoint[index].invNorm,
+ n1, n2, n3, tPoint->barycentricWeights[0].v);
+ mul_mat3_m4_v3(ob->obmat, bPoint[index].invNorm);
+ normalize_v3(bPoint[index].invNorm);
+ negate_v3(bPoint[index].invNorm);
+ }
+ else {
+ if (tPoint->quad) {VECCOPY(bPoint[index].invNorm, canvasInvNormals[tPoint->face_index].no_q);}
+ else {VECCOPY(bPoint[index].invNorm, canvasInvNormals[tPoint->face_index].no);}
+ }
+ }
+ else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+ /* In case of verted data */
+
+ /* location */
+ VECCOPY(bPoint[index].realCoord, canvasVerts[index].v);
+
+ /* normal */
+ normal_short_to_float_v3(bPoint[index].invNorm, mvert[index].no);
+ mul_mat3_m4_v3(ob->obmat, bPoint[index].invNorm);
+ normalize_v3(bPoint[index].invNorm);
+ //mul_qt_v3(ob->quat, bPoint[index].invNorm);
+ negate_v3(bPoint[index].invNorm);
+ }
- cPoint->depth -= 1.0f/canvas->dflat_speed*timescale;
- if (cPoint->depth < 0.0f) cPoint->depth = 0.0f;
- }
+ /* Prepare special data for surface types */
+ if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
+ 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;}
+ mul_v3_v3 (temp_nor, ob->size);
+ bPoint[index].normal_scale = len_v3(temp_nor);
+ }
- /*
- * Calculate current 3D-position of each texture pixel
- */
- interp_v3_v3v3v3( cPoint->realCoord,
- canvasVerts[cPoint->v1].v,
- canvasVerts[cPoint->v2].v,
- canvasVerts[cPoint->v3].v, cPoint->barycentricWeights[0].v);
-
- /* Calculate current pixel surface normal */
- if(mface[cPoint->index].flag & ME_SMOOTH) {
- normal_short_to_float_v3(n1, mvert[cPoint->v1].no);
- normal_short_to_float_v3(n2, mvert[cPoint->v2].no);
- normal_short_to_float_v3(n3, mvert[cPoint->v3].no);
-
- interp_v3_v3v3v3( cPoint->invNorm,
- n1, n2, n3, cPoint->barycentricWeights[0].v);
- normalize_v3(cPoint->invNorm);
- negate_v3(cPoint->invNorm);
- }
- else {
- if (cPoint->quad) {VECCOPY(cPoint->invNorm, canvasInvNormals[cPoint->index].no_q);}
- else {VECCOPY(cPoint->invNorm, canvasInvNormals[cPoint->index].no);}
- }
+ /*
+ * TODO: paint effect space preparation
+ */
+ }
+ MEM_freeN(canvasVerts);
+ MEM_freeN(canvasInvNormals);
- /*
- * Get current gravity direction of pixel in UV space.
- * World gravity direction is negative z-axis
- * - if any active effect requires it
- */
- if (canvas->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
-
- cPoint->gravity_dir = 0.0f;
- cPoint->gravity_rate = 1.0f - abs(cPoint->invNorm[2]);
+ return 1;
+}
- if (cPoint->gravity_rate > 0.01)
- {
- float uv1[3], uv2[3], uv3[3], unormal[3];
- int v2i, v3i;
+static void scene_updateObject(Scene *scene, Object *ob, float frame) {
+ int oflags;
+ /* backup object flags */
+ oflags = ob->recalc;
- v2i = (cPoint->quad) ? 2 : 1;
- v3i = (cPoint->quad) ? 3 : 2;
- /*
- * Apply z-coodrinate (gravity dir) to uv-vertices
- */
- uv1[0] = tface[cPoint->index].uv[0][0];
- uv1[1] = tface[cPoint->index].uv[0][1];
- uv1[2] = canvasVerts[cPoint->v1].v[2];
+ ob->recalc |= OB_RECALC_ALL;
+ ob->recalc |= OB_RECALC_DATA;
+ BKE_animsys_evaluate_animdata(&ob->id, ob->adt, frame, ADT_RECALC_ANIM);
+ object_handle_update(scene, ob);
- uv2[0] = tface[cPoint->index].uv[v2i][0];
- uv2[1] = tface[cPoint->index].uv[v2i][1];
- uv2[2] = canvasVerts[cPoint->v2].v[2];
+ /* restore flags */
+ ob->recalc = oflags;
+}
- uv3[0] = tface[cPoint->index].uv[v3i][0];
- uv3[1] = tface[cPoint->index].uv[v3i][1];
- uv3[2] = canvasVerts[cPoint->v3].v[2];
+static void scene_setSubframe(Scene *scene, float subframe) {
+ /* dynamic paint subframes must be done on previous frame */
+ scene->r.cfra -= 1;
+ scene->r.subframe = subframe;
+}
- /* Calculate a new normal vector for that generated face */
- normal_tri_v3( unormal, uv1, uv2, uv3);
+/*
+* 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;
+ DynamicPaintCanvasSettings *canvas = surface->canvas;
+ PaintBakePoint *bPoint;
- /* Normalize u and v part of it */
- normalize_v2(unormal);
+ if (!sData || sData->total_points < 1) return 0;
- /*
- * use direction of that 2d vector as gravity direction in uv space
- * (Convert from -pi->pi to 0->2pi to use with neighbour table)
- */
- cPoint->gravity_dir = fmod((atan2(unormal[1], unormal[0])+6.28318531f), 6.28318531f);
- }
- } // end if (effect)
- } // end i>0
- } // yy
- } // end of loop xx
- MEM_freeN(canvasInvNormals);
+ /* Init surface current frame position data */
+ bPoint = (struct PaintBakePoint *) MEM_mallocN(sData->total_points*sizeof(struct PaintBakePoint), "Dynamic Paint step data");
+ if (bPoint == NULL) return printError(canvas, "Not enough free memory.");
+ if (!dynamicPaint_prepareSurfaceStep(surface, bPoint, ob, canvas->dm, timescale))
+ return printError(canvas, "Not enough free memory.");
/*
- * Loop through every object in scene and
- * do painting for active paint objects
+ * Loop through surface's target paint objects and do painting
*/
{
- Object *otherobj = NULL;
+ Base *base = NULL;
+ GroupObject *go = NULL;
+
+ Object *brushObj = NULL;
ModifierData *md = NULL;
- base = scene->base.first;
+ /* backup current scene frame */
+ int scene_frame = scene->r.cfra;
+ float scene_subframe = scene->r.subframe;
- while(base)
- {
- otherobj = base->object;
+ /* either from group or from all objects */
+ if(surface->brush_group)
+ go = surface->brush_group->gobject.first;
+ else
+ base = scene->base.first;
- if(!otherobj)
- {
- base= base->next;
+ while (base || go)
+ {
+ brushObj = NULL;
+
+ /* select object */
+ if(surface->brush_group) {
+ if(go->ob) brushObj = go->ob;
+ }
+ else
+ brushObj = base->object;
+
+ if(!brushObj)
+ {
+ /* skip item */
+ if(surface->brush_group) go = go->next;
+ else base= base->next;
continue;
}
- base= base->next;
- md = modifiers_findByType(otherobj, eModifierType_DynamicPaint);
+ /* next item */
+ if(surface->brush_group)
+ go = go->next;
+ else
+ base= base->next;
+
+ md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
/* check if target has an active dp modifier */
if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render))
@@ -2852,257 +2993,113 @@ static int DynamicPaint_DoStep(Scene *scene, Object *ob, DynamicPaintModifierDat
DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md;
/* Make sure we're dealing with a painter */
- if((pmd2->type & MOD_DYNAMICPAINT_TYPE_PAINT) && pmd2->paint)
+ if((pmd2->type & MOD_DYNAMICPAINT_TYPE_BRUSH) && pmd2->brush)
{
- DynamicPaintPainterSettings *paint = pmd2->paint;
+ DynamicPaintBrushSettings *brush = pmd2->brush;
- /*
- * Make sure at least one influence is enabled
- */
- if (!(paint->flags & MOD_DPAINT_DO_PAINT || paint->flags & MOD_DPAINT_DO_DISPLACE)) continue;
+ /* update object position on this subframe */
+ if (subframe) {
+ scene_setSubframe(scene, subframe);
+ scene_updateObject(scene, brushObj, BKE_curframe(scene));
+ }
/* Check if painter has a particle system selected
* -> if so, do particle painting */
- if (paint->collision == MOD_DPAINT_COL_PSYS)
+ if (brush->collision == MOD_DPAINT_COL_PSYS)
{
- if (paint && paint->psys && paint->psys->part && paint->psys->part->type==PART_EMITTER)
- if (psys_check_enabled(otherobj, paint->psys)) {
+ if (brush && brush->psys && brush->psys->part && brush->psys->part->type==PART_EMITTER)
+ if (psys_check_enabled(brushObj, brush->psys)) {
/*
* Paint a particle system
*/
- DynamicPaint_PaintParticles(canvas, paint->psys, paint, ob, timescale);
+ dynamicPaint_paintParticles(surface, bPoint, brush->psys, brush, ob, timescale);
}
}
else {
/*
* Paint a object mesh
*/
- DynamicPaint_PaintMesh(canvas, canvasVerts, paint, ob, otherobj, timescale);
+ dynamicPaint_paintMesh(surface, bPoint, brush, ob, brushObj, timescale);
+ }
+
+ /* return object to it's original state */
+ if (subframe) {
+ scene->r.cfra = scene_frame;
+ scene->r.subframe = scene_subframe;
+ scene_updateObject(scene, brushObj, BKE_curframe(scene));
}
} /* end of collision check (Is valid paint modifier) */
}
}
}
- /* Free per frame canvas data */
- MEM_freeN(canvasVerts);
-
-
- /*
- * DO EFFECTS
- */
- if (canvas->effect)
- {
- unsigned int steps = 1, s;
-
- /* Allocate memory for surface previous points to read unchanged values from */
- PaintSurfacePoint *prevPoint = (struct PaintSurfacePoint *) MEM_mallocN(surface->w*surface->h*sizeof(struct PaintSurfacePoint), "PaintSurfaceDataTemp");
- if (prevPoint == NULL) {dpError(canvas, "Not enough free memory."); return 0;}
-
- /* Prepare effects and get number of required effect-substeps */
- steps = DynamicPaint_Prepare_EffectStep(canvas, timescale);
-
- /*
- * Do Effects steps
- */
- for (s = 0; s < steps; s++)
- {
- /* Copy current surface to the previous surface array */
- memcpy(prevPoint, surface->point, surface->w*surface->h*sizeof(struct PaintSurfacePoint));
-
- DynamicPaint_Do_EffectStep(canvas, prevPoint, timescale);
-
- }
-
- /* Free temporary effect data */
- MEM_freeN(prevPoint);
- DynamicPaint_Clean_EffectStep(canvas, timescale);
-
- } // end effects
+ MEM_freeN(bPoint);
return 1;
}
-
/*
-* Outputs an image file from canvas data.
+* Calculate a single frame for canvas point cache
*/
-void dynamic_paint_output_image(struct DynamicPaintCanvasSettings *canvas, char* filename, short type, short source)
+static int dynamicPaint_calculateFrame(DynamicPaintSurface *surface, Scene *scene, Object *cObject, int frame)
{
- int yy;
- ImBuf* mhImgB = NULL;
-
- int tWidth, tHeight;
- PaintSurface *surface = canvas->surface;
-
- if (!surface) {printf("Canvas save failed: Invalid surface.\n");return;}
-
- /* Validate output file path */
- BLI_path_abs(filename, G.main->name);
- BLI_make_existing_file(filename);
-
- /* Print save message */
- if (source == DPOUTPUT_WET) {
- printf("Saving wetmap : %s\n", filename);
- } else if (source == DPOUTPUT_DISPLACE) {
- printf("Saving displacement map : %s\n", filename);
- } else {
- printf("Saving color map : %s\n", filename);
- }
-
- tWidth = surface->w;
- tHeight = surface->h;
-
- /* Init image buffer */
- mhImgB = IMB_allocImBuf(tWidth, tHeight, 32, IB_rectfloat);
- if (mhImgB == NULL) {printf("Image save failed: Not enough free memory.\n");return;}
+ float timescale = 1.0f;
+
+ /* dont do substeps for first frame */
+ if (surface->substeps && (frame != surface->start_frame)) {
+ int st;
+ timescale = 1.0f / (surface->substeps+1);
- #pragma omp parallel for schedule(static)
- for (yy = 0; yy < tHeight; yy++)
+ for (st = 1; st <= surface->substeps; st++)
{
- int xx;
- for (xx = 0; xx < tWidth; xx++)
- {
- int pos=(xx+tWidth*yy)*4; /* image buffer position */
- int index=(xx+tWidth*yy); /* surface point */
- PaintSurfacePoint *cPoint = (&surface->point[index]);
-
-
- /* Set values of preferred type */
- if (source == DPOUTPUT_WET) {
- float value = (cPoint->wetness > 1.0f) ? 1.0f : cPoint->wetness;
- mhImgB->rect_float[pos]=value;
- mhImgB->rect_float[pos+1]=value;
- mhImgB->rect_float[pos+2]=value;
- mhImgB->rect_float[pos+3]=1.0f;
- }
- else if (source == DPOUTPUT_DISPLACE) {
-
- float depth = cPoint->depth;
-
- if (canvas->disp_type == MOD_DPAINT_DISP_DISPLACE) {
- depth = (0.5f - depth);
- if (depth < 0.0f) depth = 0.0f;
- if (depth > 1.0f) depth = 1.0f;
- }
-
- mhImgB->rect_float[pos]=depth;
- mhImgB->rect_float[pos+1]=depth;
- mhImgB->rect_float[pos+2]=depth;
- mhImgB->rect_float[pos+3]=1.0f;
- }
- else { /* DPOUTPUT_PAINT */
-
- float invAlpha = 1.0f - cPoint->e_alpha;
-
- /* If base layer already has a color, blend it */
- if (cPoint->alpha) {
- mhImgB->rect_float[pos] = cPoint->color[0] * invAlpha + cPoint->e_color[0] * cPoint->e_alpha;
- mhImgB->rect_float[pos+1] = cPoint->color[1] * invAlpha + cPoint->e_color[1] * cPoint->e_alpha;
- mhImgB->rect_float[pos+2] = cPoint->color[2] * invAlpha + cPoint->e_color[2] * cPoint->e_alpha;
- }
- else {
- /* Else use effect layer color */
- mhImgB->rect_float[pos] = cPoint->e_color[0];
- mhImgB->rect_float[pos+1] = cPoint->e_color[1];
- mhImgB->rect_float[pos+2] = cPoint->e_color[2];
- }
-
- /* Set use highest alpha */
- mhImgB->rect_float[pos+3] = (cPoint->e_alpha > cPoint->alpha) ? cPoint->e_alpha : cPoint->alpha;
-
- /* Multiply color by alpha if enabled */
- if (canvas->flags & MOD_DPAINT_MULALPHA) {
- mhImgB->rect_float[pos] *= mhImgB->rect_float[pos+3];
- mhImgB->rect_float[pos+1] *= mhImgB->rect_float[pos+3];
- mhImgB->rect_float[pos+2] *= mhImgB->rect_float[pos+3];
- }
- }
- }
- }
-
- /* Save image buffer */
- if (type == DPOUTPUT_JPEG) { /* JPEG */
- mhImgB->ftype= JPG|95;
- IMB_rect_from_float(mhImgB);
- imb_savejpeg(mhImgB, filename, IB_rectfloat);
- }
-#ifdef WITH_OPENEXR
- else if (type == DPOUTPUT_OPENEXR) { /* OpenEXR 32-bit float */
- mhImgB->ftype = OPENEXR | OPENEXR_COMPRESS;
- IMB_rect_from_float(mhImgB);
- imb_save_openexr(mhImgB, filename, IB_rectfloat);
- }
-#endif
- else { /* DPOUTPUT_PNG */
- mhImgB->ftype= PNG|95;
- IMB_rect_from_float(mhImgB);
- imb_savepng(mhImgB, filename, IB_rectfloat);
- }
-
- IMB_freeImBuf(mhImgB);
-}
-
-
-/*
-* Update required data that didn't get updated
-* by ED_update_for_newframe()
-*/
-static void update_scene_data(struct Main *bmain, int frame)
-{
+ float subframe = ((float) st) / (surface->substeps+1);
- Tex *tex;
- /*
- * Loop through textures and update voxel data
- */
- for (tex= bmain->tex.first; tex; tex= tex->id.next) {
- if(tex->id.us && tex->type==TEX_VOXELDATA) {
- cache_voxeldata(tex, frame);
+ if (!dynamicPaint_doStep(scene, cObject, surface, timescale, subframe)) return 0;
}
}
+
+ if (!dynamicPaint_doStep(scene, cObject, surface, timescale, 0.0f)) return 0;
+ else return 1;
}
+/***************************** Image Sequence Baking ******************************/
/*
-* Do actual bake operation.
-* returns 0 on failture.
+* Do actual bake operation. Loops through to-be-baked frames.
+* Returns 0 on failture.
*/
-static int DynamicPaint_Bake(bContext *C, struct DynamicPaintModifierData *pmd, Object *cObject)
+static int dynamicPaint_bakeImageSequence(bContext *C, DynamicPaintSurface *surface, Object *cObject)
{
-
- DynamicPaintCanvasSettings *canvas;
+ DynamicPaintCanvasSettings *canvas = surface->canvas;
Scene *scene= CTX_data_scene(C);
wmWindow *win = CTX_wm_window(C);
int frame = 1;
int frames;
- canvas = pmd->canvas;
- if (!canvas) {dpError(canvas, "Invalid canvas."); return 0;}
-
- frames = canvas->end_frame - canvas->start_frame + 1;
- if (frames <= 0) {dpError(canvas, "No frames to bake."); return 0;}
+ frames = surface->end_frame - surface->start_frame + 1;
+ if (frames <= 0) {return printError(canvas, "No frames to bake.");}
/*
* Set frame to start point (also inits modifier data)
*/
- frame = canvas->start_frame;
+ frame = surface->start_frame;
scene->r.cfra = (int)frame;
ED_update_for_newframe(CTX_data_main(C), scene, win->screen, 1);
- update_scene_data(CTX_data_main(C), frame);
/* Init surface */
- if (!dynamicPaint_createCanvasSurface(canvas)) return 0;
+ if (!dynamicPaint_createUVSurface(surface)) return 0;
/*
* Loop through selected frames
*/
- for (frame=canvas->start_frame; frame<=canvas->end_frame; frame++)
+ for (frame=surface->start_frame; frame<=surface->end_frame; frame++)
{
- float timescale = 1.0f / (canvas->substeps+1);
+ float timescale = 1.0f / (surface->substeps+1);
int st;
- float progress = (frame - canvas->start_frame) / (float)frames * 100;
+ float progress = (frame - surface->start_frame) / (float)frames * 100;
+ surface->current_frame = frame;
/* If user requested stop (esc), quit baking */
if (blender_test_break()) return 0;
@@ -3116,48 +3113,31 @@ static int DynamicPaint_Bake(bContext *C, struct DynamicPaintModifierData *pmd,
* Do calculations for every substep
* Note: these have to be from previous frame
*/
- if (frame != canvas->start_frame) {
- for (st = 1; st <= canvas->substeps; st++)
- {
- float subframe = ((float) st) / (canvas->substeps+1);
-
- /* Update frame if we have proceed */
- scene->r.cfra = (int)frame - 1;
- scene->r.subframe = subframe;
- ED_update_for_newframe(CTX_data_main(C), scene, win->screen, 1);
-
- if (!DynamicPaint_DoStep(scene, cObject, pmd, timescale)) return 0;
- }
-
- /*
- * Change to next whole frame
- */
+ if (frame != surface->start_frame) {
+ /* change to next frame */
scene->r.cfra = (int)frame;
scene->r.subframe = 0.0f;
ED_update_for_newframe(CTX_data_main(C), scene, win->screen, 1);
- update_scene_data(CTX_data_main(C), frame);
-
- }
- if (!DynamicPaint_DoStep(scene, cObject, pmd, timescale)) return 0;
+ for (st = 1; st <= surface->substeps; st++)
+ {
+ float subframe = ((float) st) / (surface->substeps+1);
- /*
- * Just in case, check if any output is enabled
- * Don't cancel the bake because user may have keyframed outputs
- */
- if (!(canvas->output & MOD_DPAINT_OUT_PAINT || canvas->output & MOD_DPAINT_OUT_WET || canvas->output & MOD_DPAINT_OUT_DISP)) {
- printf("Skipping output for frame %i.\n", frame);
- continue;
+ if (!dynamicPaint_doStep(scene, cObject, surface, timescale, subframe)) return 0;
+ }
}
+ if (!dynamicPaint_doStep(scene, cObject, surface, timescale, 0.0f)) return 0;
+
/*
* Save output images
*/
{
char filename[250];
char pad[4];
- char wet[4];
- char disp[4];
+ char dir_slash[2];
+ /* OpenEXR or PNG */
+ int format = (surface->image_fileformat & MOD_DPAINT_IMGFORMAT_OPENEXR) ? DPOUTPUT_OPENEXR : DPOUTPUT_PNG;
/* Add frame number padding */
if (frame<10) sprintf(pad,"000");
@@ -3165,139 +3145,72 @@ static int DynamicPaint_Bake(bContext *C, struct DynamicPaintModifierData *pmd,
else if (frame<1000) sprintf(pad,"0");
else pad[0] = '\0';
- /* Check if paint and wet map filename is same and fix if necessary */
- if (!strcmp(canvas->paint_output_path, canvas->wet_output_path)) sprintf(wet,"wet");
- else wet[0] = '\0';
- /* same for displacement map */
- if (!strcmp(canvas->paint_output_path, canvas->displace_output_path)) sprintf(disp,"disp");
- else if (!strcmp(canvas->wet_output_path, canvas->displace_output_path)) sprintf(disp,"disp");
- else disp[0] = '\0';
+ /* make sure directory path is valid to append filename */
+ if (surface->image_output_path[strlen(surface->image_output_path)-1] != 47 &&
+ surface->image_output_path[strlen(surface->image_output_path)-1] != 92)
+ strcpy(dir_slash,"/");
+ else
+ dir_slash[0] = '\0';
- /* color map */
- if (canvas->output & MOD_DPAINT_OUT_PAINT) {
- sprintf(filename, "%s%s%i.png", canvas->paint_output_path, pad, (int)frame);
- dynamic_paint_output_image(canvas, filename, DPOUTPUT_PNG, DPOUTPUT_PAINT);
- }
-
- /* wetmap */
- if (canvas->output & MOD_DPAINT_OUT_WET) {
- sprintf(filename, "%s%s%s%i.png", canvas->wet_output_path, wet, pad, (int)frame);
+ /* 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);
- dynamic_paint_output_image(canvas, filename, DPOUTPUT_PNG, DPOUTPUT_WET);
+ 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 */
- if (canvas->output & MOD_DPAINT_OUT_DISP) {
- /* OpenEXR or PNG */
- int format = (canvas->disp_format & MOD_DPAINT_DISPFOR_OPENEXR) ? DPOUTPUT_OPENEXR : DPOUTPUT_PNG;
- char ext[4];
- if (canvas->disp_format & MOD_DPAINT_DISPFOR_OPENEXR) sprintf(ext,"exr"); else sprintf(ext,"png");
- sprintf(filename, "%s%s%s%i.%s", canvas->displace_output_path, disp, pad, (int)frame, ext);
-
- dynamic_paint_output_image(canvas, filename, format, DPOUTPUT_DISPLACE);
+ if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
+ sprintf(filename, "%s%s%s%s%i", surface->image_output_path, dir_slash, surface->output_name, pad, (int)frame);
+ dynamicPaint_outputImage(surface, filename, format, DPOUTPUT_DISPLACE);
}
}
}
-
return 1;
}
/*
-* Updates baking status for every paint object in the scene
-* returns 0 if no paint objects found.
+* An operator call to start baking dynamic paint image sequences for active object
*/
-static int DynamicPaint_PainterSetBaking(Scene *scene, short baking)
+static int dynamicPaint_initBake(bContext *C, wmOperator *op)
{
- Object *otherobj = NULL;
- ModifierData *md = NULL;
- int count = 0;
-
- Base *base = scene->base.first;
-
- while(base)
- {
-
- otherobj = base->object;
-
- if(!otherobj)
- {
- base= base->next;
- continue;
- }
-
- md = modifiers_findByType(otherobj, eModifierType_DynamicPaint);
-
- /* check if target has an active dp modifier */
- if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render))
- {
- DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md;
- /* Make sure we're dealing with a painter */
- if((pmd2->type & MOD_DYNAMICPAINT_TYPE_PAINT) && pmd2->paint)
- {
- pmd2->baking = baking;
- count++;
- }
- }
- base= base->next;
- }
-
- if (count) return 1;
-
- return 0;
-}
-
-
-/*
-* An operator call to bake dynamic paint simulation for active object
-*/
-static int dynamic_paint_bake_all(bContext *C, wmOperator *op)
-{
-
DynamicPaintModifierData *pmd = NULL;
- Scene *scene = CTX_data_scene(C);
Object *cObject = CTX_data_active_object(C);
int status = 0;
double timer = PIL_check_seconds_timer();
+ DynamicPaintSurface *surface;
/*
* Get modifier data
*/
pmd = (DynamicPaintModifierData *)modifiers_findByType(cObject, eModifierType_DynamicPaint);
- if (!pmd) {printf("DynamicPaint bake failed: No Dynamic Paint modifier found.\n"); return 0;}
+ if (!pmd) {
+ BKE_report(op->reports, RPT_ERROR, "Bake Failed: No Dynamic Paint modifier found.");
+ return 0;
+ }
/* Make sure we're dealing with a canvas */
- if (!pmd->canvas) {printf("DynamicPaint bake failed: Invalid canvas.\n"); return 0;}
+ if (!pmd->canvas) {
+ BKE_report(op->reports, RPT_ERROR, "Bake Failed: Invalid Canvas.");
+ return 0;
+ }
+ surface = get_activeSurface(pmd->canvas);
- /*
- * Set state to baking and init surface
- */
+ /* Set state to baking and init surface */
pmd->canvas->error[0] = '\0';
- pmd->baking = 1;
-
- if (DynamicPaint_PainterSetBaking(scene, 1)) {
-
- G.afbreek= 0; /* reset blender_test_break*/
+ pmd->canvas->flags |= MOD_DPAINT_BAKING;
+ G.afbreek= 0; /* reset blender_test_break*/
- /* Bake Dynamic Paint */
- status = DynamicPaint_Bake(C, pmd, cObject);
-
- /*
- * Clean bake stuff
- */
- pmd->baking = 0;
- DynamicPaint_PainterSetBaking(scene, 0);
- dynamicPaint_cleanCanvasSurface(pmd->canvas);
-
- /* Restore cursor back to normal */
- WM_cursor_restore(CTX_wm_window(C));
-
- }
- else {
- dpError(pmd->canvas, "No paint objects.");
- status = 0;
- }
+ /* Bake Dynamic Paint */
+ status = dynamicPaint_bakeImageSequence(C, surface, cObject);
+ /* Clean bake flag */
+ pmd->canvas->flags &= ~MOD_DPAINT_BAKING;
+ /* Restore cursor back to normal */
+ WM_cursor_restore(CTX_wm_window(C));
/* Bake was successful:
* Report for ended bake and how long it took */
@@ -3341,7 +3254,6 @@ static int dynamic_paint_bake_all(bContext *C, wmOperator *op)
/* Print failed bake to console */
printf("Baking Cancelled!\n");
-
}
return status;
@@ -3354,7 +3266,7 @@ static int dynamicpaint_bake_exec(bContext *C, wmOperator *op)
{
/* Bake dynamic paint */
- if(!dynamic_paint_bake_all(C, op)) {
+ if(!dynamicPaint_initBake(C, op)) {
return OPERATOR_CANCELLED;}
return OPERATOR_FINISHED;
@@ -3372,3 +3284,91 @@ void DPAINT_OT_bake(wmOperatorType *ot)
ot->poll= ED_operator_object_active_editable;
}
+static int surface_slot_add_exec(bContext *C, wmOperator *op)
+{
+ DynamicPaintModifierData *pmd = NULL;
+ Object *cObject = CTX_data_active_object(C);
+ DynamicPaintSurface *surface;
+
+ /* Make sure we're dealing with a canvas */
+ pmd = (DynamicPaintModifierData *)modifiers_findByType(cObject, eModifierType_DynamicPaint);
+ if (!pmd) return OPERATOR_CANCELLED;
+ if (!pmd->canvas) return OPERATOR_CANCELLED;
+
+ surface = dynamicPaint_createNewSurface(pmd->canvas);
+
+ if (!surface) return OPERATOR_CANCELLED;
+
+ /* set preview for this surface only and set active */
+ pmd->canvas->active_sur = 0;
+ for(surface=surface->prev; surface; surface=surface->prev) {
+ surface->flags &= ~MOD_DPAINT_PREVIEW;
+ pmd->canvas->active_sur++;
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+/* add surface slot */
+void DPAINT_OT_surface_slot_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Add Surface Slot";
+ ot->idname= "DPAINT_OT_surface_slot_add";
+ ot->description="Add a new Dynamic Paint surface slot";
+
+ /* api callbacks */
+ ot->exec= surface_slot_add_exec;
+ ot->poll= ED_operator_object_active_editable;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int surface_slot_remove_exec(bContext *C, wmOperator *op)
+{
+ DynamicPaintModifierData *pmd = NULL;
+ Object *cObject = CTX_data_active_object(C);
+ DynamicPaintSurface *surface;
+ int id=0;
+
+ /* Make sure we're dealing with a canvas */
+ pmd = (DynamicPaintModifierData *)modifiers_findByType(cObject, eModifierType_DynamicPaint);
+ if (!pmd) return OPERATOR_CANCELLED;
+ if (!pmd->canvas) return OPERATOR_CANCELLED;
+
+ surface = pmd->canvas->surfaces.first;
+
+ /* find active surface and remove it */
+ for(; surface; surface=surface->next) {
+ if(id == pmd->canvas->active_sur) {
+ pmd->canvas->active_sur -= 1;
+ dynamicPaint_freeSurface(surface);
+ break;
+ }
+ id++;
+ }
+
+ dynamicPaint_resetPreview(pmd->canvas);
+ DAG_id_tag_update(&cObject->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, cObject);
+
+ return OPERATOR_FINISHED;
+}
+
+/* remove surface slot */
+void DPAINT_OT_surface_slot_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Remove Surface Slot";
+ ot->idname= "DPAINT_OT_surface_slot_remove";
+ ot->description="Remove the selected surface slot";
+
+ /* api callbacks */
+ ot->exec= surface_slot_remove_exec;
+ ot->poll= ED_operator_object_active_editable;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 251aa7259d7..56f02762ea6 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -3459,9 +3459,9 @@ void object_remove_particle_system(Scene *scene, Object *ob)
if((md = modifiers_findByType(ob, eModifierType_DynamicPaint)))
{
DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
- if((pmd->type == MOD_DYNAMICPAINT_TYPE_PAINT) && pmd->paint && pmd->paint->psys)
- if(pmd->paint->psys == psys)
- pmd->paint->psys = NULL;
+ if((pmd->type == MOD_DYNAMICPAINT_TYPE_BRUSH) && pmd->brush && pmd->brush->psys)
+ if(pmd->brush->psys == psys)
+ pmd->brush->psys = NULL;
}
/* clear modifier */
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 64893bb0b5b..e92ba11826e 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -40,6 +40,7 @@
#include "DNA_ID.h"
#include "DNA_cloth_types.h"
+#include "DNA_dynamicpaint_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force.h"
@@ -60,6 +61,7 @@
#include "BKE_blender.h"
#include "BKE_cloth.h"
#include "BKE_depsgraph.h"
+#include "BKE_dynamicpaint.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
@@ -602,7 +604,7 @@ static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
return ret;
}
-static void ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
+static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
{
SmokeModifierData *smd= (SmokeModifierData *)smoke_v;
SmokeDomainSettings *sds = smd->domain;
@@ -651,6 +653,82 @@ static void ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
ptcache_file_compressed_read(pf, (unsigned char*)tcw, out_len);
}
}
+
+ return 1;
+}
+
+static int ptcache_dynamicpaint_totpoint(void *sd, int cfra)
+{
+ DynamicPaintSurface *surface = (DynamicPaintSurface*)sd;
+
+ if (!surface->data) return 0;
+ else return surface->data->total_points;
+}
+
+#define DP_CACHE_VERSION "1.01"
+
+static int ptcache_dynamicpaint_write(PTCacheFile *pf, void *dp_v)
+{
+ DynamicPaintSurface *surface = (DynamicPaintSurface*)dp_v;
+ int cache_compress = 1;
+
+ /* version header */
+ ptcache_file_write(pf, DP_CACHE_VERSION, 1, sizeof(char)*4);
+
+ if(surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ && surface->data) {
+ unsigned int total_points=surface->data->total_points;
+ unsigned int in_len;
+ unsigned char *out;
+
+ /* cache type */
+ ptcache_file_write(pf, &surface->type, 1, sizeof(int));
+
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ in_len = sizeof(PaintPoint)*total_points;
+ out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len), "pointcache_lzo_buffer");
+ }
+ else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
+ in_len = sizeof(float)*total_points;
+ out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len), "pointcache_lzo_buffer");
+ }
+ else return 0;
+
+ ptcache_file_compressed_write(pf, (unsigned char *)surface->data->type_data, in_len, out, cache_compress);
+ MEM_freeN(out);
+
+ }
+ return 1;
+}
+static int ptcache_dynamicpaint_read(PTCacheFile *pf, void *dp_v)
+{
+ DynamicPaintSurface *surface = (DynamicPaintSurface*)dp_v;
+ char version[4];
+
+ /* version header */
+ ptcache_file_read(pf, version, 1, sizeof(char)*4);
+ if (strncmp(version, DP_CACHE_VERSION,4)) {printf("Dynamic Paint: Invalid cache version: %s!\n",version); return 0;}
+
+ if(surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ && surface->data) {
+ unsigned int data_len;
+ int surface_type;
+
+ /* cache type */
+ ptcache_file_read(pf, &surface_type, 1, sizeof(int));
+
+ if (surface_type != surface->type)
+ return 0;
+
+ /* read surface data */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT)
+ data_len = sizeof(PaintPoint);
+ else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE)
+ data_len = sizeof(float);
+ else return 0;
+
+ ptcache_file_compressed_read(pf, (unsigned char*)surface->data->type_data, data_len*surface->data->total_points);
+
+ }
+ return 1;
}
/* Creating ID's */
@@ -805,6 +883,40 @@ void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeMo
if(sds->wt)
pid->data_types |= (1<<BPHYS_DATA_SMOKE_HIGH);
}
+
+void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, Object *ob, DynamicPaintSurface *surface)
+{
+
+ memset(pid, 0, sizeof(PTCacheID));
+
+ pid->ob= ob;
+ pid->calldata= surface;
+ pid->type= PTCACHE_TYPE_DYNAMICPAINT;
+ pid->cache= surface->pointcache;
+ pid->cache_ptr= &surface->pointcache;
+ pid->ptcaches= &surface->ptcaches;
+ pid->totpoint= pid->totwrite= ptcache_dynamicpaint_totpoint;
+
+ pid->write_point = NULL;
+ pid->read_point = NULL;
+ pid->interpolate_point = NULL;
+
+ pid->write_stream = ptcache_dynamicpaint_write;
+ pid->read_stream = ptcache_dynamicpaint_read;
+
+ pid->write_extra_data = NULL;
+ pid->read_extra_data = NULL;
+ pid->interpolate_extra_data = NULL;
+
+ pid->write_header = ptcache_basic_header_write;
+ pid->read_header = ptcache_basic_header_read;
+
+ pid->data_types= BPHYS_DATA_DYNAMICPAINT;
+ pid->info_types= 0;
+
+ pid->stack_index = pid->cache->index;
+}
+
void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int duplis)
{
PTCacheID *pid;
@@ -845,7 +957,7 @@ void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int dup
BKE_ptcache_id_from_cloth(pid, ob, (ClothModifierData*)md);
BLI_addtail(lb, pid);
}
- if(md->type == eModifierType_Smoke) {
+ else if(md->type == eModifierType_Smoke) {
SmokeModifierData *smd = (SmokeModifierData *)md;
if(smd->type & MOD_SMOKE_TYPE_DOMAIN)
{
@@ -854,6 +966,19 @@ void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int dup
BLI_addtail(lb, pid);
}
}
+ else if(md->type == eModifierType_DynamicPaint) {
+ DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
+ if(pmd->type & MOD_DYNAMICPAINT_TYPE_CANVAS)
+ {
+ DynamicPaintSurface *surface = pmd->canvas->surfaces.first;
+
+ for (; surface; surface=surface->next) {
+ pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID");
+ BKE_ptcache_id_from_dynamicpaint(pid, ob, surface);
+ BLI_addtail(lb, pid);
+ }
+ }
+ }
}
if(scene && (duplis-- > 0) && (ob->transflag & OB_DUPLI)) {
@@ -1586,7 +1711,8 @@ static int ptcache_read_stream(PTCacheID *pid, int cfra)
ptcache_file_pointers_init(pf);
// we have stream reading here
- pid->read_stream(pf, pid->calldata);
+ if (!pid->read_stream(pf, pid->calldata))
+ error = 1;
}
ptcache_file_close(pf);
@@ -1722,15 +1848,21 @@ int BKE_ptcache_read(PTCacheID *pid, float cfra)
return 0;
if(cfra1) {
- if(pid->read_stream)
- ptcache_read_stream(pid, cfra1);
+
+ if(pid->read_stream) {
+ if (!ptcache_read_stream(pid, cfra1))
+ return 0;
+ }
else if(pid->read_point)
ptcache_read(pid, cfra1);
}
if(cfra2) {
- if(pid->read_stream)
- ptcache_read_stream(pid, cfra2);
+
+ if(pid->read_stream) {
+ if (!ptcache_read_stream(pid, cfra2))
+ return 0;
+ }
else if(pid->read_point) {
if(cfra1 && cfra2 && pid->interpolate_point)
ptcache_interpolate(pid, cfra, cfra1, cfra2);
@@ -2278,6 +2410,8 @@ int BKE_ptcache_id_reset(Scene *scene, PTCacheID *pid, int mode)
smokeModifier_reset(pid->calldata);
else if(pid->type == PTCACHE_TYPE_SMOKE_HIGHRES)
smokeModifier_reset_turbulence(pid->calldata);
+ else if(pid->type == PTCACHE_TYPE_DYNAMICPAINT)
+ dynamicPaint_resetSurface((DynamicPaintSurface*)pid->calldata);
}
if(clear)
BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
@@ -2334,6 +2468,18 @@ int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode)
reset |= BKE_ptcache_id_reset(scene, &pid, mode);
}
}
+ if(md->type == eModifierType_DynamicPaint) {
+ DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
+ if(pmd->type & MOD_DYNAMICPAINT_TYPE_CANVAS)
+ {
+ DynamicPaintSurface *surface = pmd->canvas->surfaces.first;
+
+ for (; surface; surface=surface->next) {
+ BKE_ptcache_id_from_dynamicpaint(&pid, ob, surface);
+ reset |= BKE_ptcache_id_reset(scene, &pid, mode);
+ }
+ }
+ }
}
if (ob->type == OB_ARMATURE)