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:
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)