2012-04-30 14:24:11 +00:00
|
|
|
/*
|
|
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
2011-05-24 07:08:58 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
2012-04-30 14:24:11 +00:00
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
2011-11-10 12:28:26 +00:00
|
|
|
* Contributor(s): Miika Hämäläinen
|
2011-05-24 07:08:58 +00:00
|
|
|
*
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
*/
|
|
|
|
|
2013-09-12 03:02:50 +00:00
|
|
|
/** \file blender/blenkernel/intern/dynamicpaint.c
|
|
|
|
* \ingroup bke
|
|
|
|
*/
|
2011-05-24 07:08:58 +00:00
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
#include <math.h>
|
2011-06-16 10:41:00 +00:00
|
|
|
#include <stdio.h>
|
2011-05-24 07:08:58 +00:00
|
|
|
|
|
|
|
#include "BLI_blenlib.h"
|
|
|
|
#include "BLI_math.h"
|
|
|
|
#include "BLI_kdtree.h"
|
2011-10-22 16:16:14 +00:00
|
|
|
#include "BLI_threads.h"
|
2011-05-24 07:08:58 +00:00
|
|
|
#include "BLI_utildefines.h"
|
|
|
|
|
2012-10-26 17:32:50 +00:00
|
|
|
#include "BLF_translation.h"
|
|
|
|
|
2011-09-05 17:06:09 +00:00
|
|
|
#include "DNA_anim_types.h"
|
2012-06-29 11:19:29 +00:00
|
|
|
#include "DNA_armature_types.h"
|
2011-12-05 13:36:41 +00:00
|
|
|
#include "DNA_constraint_types.h"
|
2011-09-05 17:06:09 +00:00
|
|
|
#include "DNA_dynamicpaint_types.h"
|
|
|
|
#include "DNA_group_types.h" /*GroupObject*/
|
2011-10-22 16:16:14 +00:00
|
|
|
#include "DNA_material_types.h"
|
2011-09-05 17:06:09 +00:00
|
|
|
#include "DNA_mesh_types.h"
|
|
|
|
#include "DNA_meshdata_types.h"
|
|
|
|
#include "DNA_modifier_types.h"
|
|
|
|
#include "DNA_object_types.h"
|
|
|
|
#include "DNA_scene_types.h"
|
2011-10-28 14:46:09 +00:00
|
|
|
#include "DNA_space_types.h"
|
2011-10-22 16:16:14 +00:00
|
|
|
#include "DNA_texture_types.h"
|
2011-09-05 17:06:09 +00:00
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
#include "BKE_animsys.h"
|
2012-06-29 11:19:29 +00:00
|
|
|
#include "BKE_armature.h"
|
2012-05-12 16:11:34 +00:00
|
|
|
#include "BKE_bvhutils.h" /* bvh tree */
|
2011-05-24 07:08:58 +00:00
|
|
|
#include "BKE_blender.h"
|
|
|
|
#include "BKE_cdderivedmesh.h"
|
2011-12-05 13:36:41 +00:00
|
|
|
#include "BKE_constraint.h"
|
2011-05-24 07:08:58 +00:00
|
|
|
#include "BKE_context.h"
|
|
|
|
#include "BKE_customdata.h"
|
|
|
|
#include "BKE_colortools.h"
|
2011-06-18 18:41:20 +00:00
|
|
|
#include "BKE_deform.h"
|
2011-06-16 10:41:00 +00:00
|
|
|
#include "BKE_depsgraph.h"
|
2011-05-24 07:08:58 +00:00
|
|
|
#include "BKE_DerivedMesh.h"
|
2011-06-16 10:41:00 +00:00
|
|
|
#include "BKE_dynamicpaint.h"
|
2011-06-27 07:30:58 +00:00
|
|
|
#include "BKE_effect.h"
|
2011-05-24 07:08:58 +00:00
|
|
|
#include "BKE_global.h"
|
2011-10-22 16:16:14 +00:00
|
|
|
#include "BKE_image.h"
|
2011-05-24 07:08:58 +00:00
|
|
|
#include "BKE_main.h"
|
|
|
|
#include "BKE_material.h"
|
|
|
|
#include "BKE_modifier.h"
|
2011-06-16 10:41:00 +00:00
|
|
|
#include "BKE_object.h"
|
2011-05-24 07:08:58 +00:00
|
|
|
#include "BKE_particle.h"
|
2011-06-16 10:41:00 +00:00
|
|
|
#include "BKE_pointcache.h"
|
|
|
|
#include "BKE_scene.h"
|
2011-05-24 07:08:58 +00:00
|
|
|
#include "BKE_texture.h"
|
|
|
|
|
2011-07-08 11:03:37 +00:00
|
|
|
#include "RNA_access.h"
|
|
|
|
#include "RNA_define.h"
|
|
|
|
#include "RNA_enum_types.h"
|
|
|
|
|
2011-05-24 07:08:58 +00:00
|
|
|
/* for image output */
|
|
|
|
#include "IMB_imbuf_types.h"
|
|
|
|
#include "IMB_imbuf.h"
|
|
|
|
|
2011-10-22 16:16:14 +00:00
|
|
|
/* to read material/texture color */
|
2011-05-24 07:08:58 +00:00
|
|
|
#include "RE_render_ext.h"
|
2011-10-22 16:16:14 +00:00
|
|
|
#include "RE_shader_ext.h"
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
#ifdef _OPENMP
|
2012-11-23 10:03:50 +00:00
|
|
|
# include <omp.h>
|
2011-07-22 18:37:30 +00:00
|
|
|
#endif
|
|
|
|
|
2012-11-04 07:18:29 +00:00
|
|
|
/* could enable at some point but for now there are far too many conversions */
|
2012-11-23 10:03:50 +00:00
|
|
|
#ifdef __GNUC__
|
|
|
|
# pragma GCC diagnostic ignored "-Wdouble-promotion"
|
|
|
|
#endif
|
2012-11-04 07:18:29 +00:00
|
|
|
|
2011-05-24 07:08:58 +00:00
|
|
|
/* precalculated gaussian factors for 5x super sampling */
|
2013-10-10 20:22:17 +00:00
|
|
|
static const float gaussianFactors[5] = {
|
|
|
|
0.996849f,
|
|
|
|
0.596145f,
|
|
|
|
0.596145f,
|
|
|
|
0.596145f,
|
|
|
|
0.524141f};
|
|
|
|
static const float gaussianTotal = 3.309425f;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-03-01 12:20:18 +00:00
|
|
|
/* UV Image neighboring pixel table x and y list */
|
2012-04-29 15:47:02 +00:00
|
|
|
static int neighX[8] = {1, 1, 0, -1, -1, -1, 0, 1};
|
|
|
|
static int neighY[8] = {0, 1, 1, 1, 0, -1, -1, -1};
|
2011-10-13 20:00:22 +00:00
|
|
|
|
|
|
|
/* subframe_updateObject() flags */
|
2013-03-22 17:08:55 +00:00
|
|
|
#define SUBFRAME_RECURSION 5
|
2012-05-12 16:11:34 +00:00
|
|
|
#define UPDATE_MESH (1 << 1)
|
2013-03-22 17:08:55 +00:00
|
|
|
#define UPDATE_EVERYTHING (UPDATE_MESH) // | UPDATE_PARENTS
|
2011-10-13 20:00:22 +00:00
|
|
|
/* surface_getBrushFlags() return vals */
|
2012-05-12 16:11:34 +00:00
|
|
|
#define BRUSH_USES_VELOCITY (1 << 0)
|
2011-10-13 20:00:22 +00:00
|
|
|
/* brush mesh raycast status */
|
|
|
|
#define HIT_VOLUME 1
|
|
|
|
#define HIT_PROXIMITY 2
|
2012-01-24 17:28:50 +00:00
|
|
|
/* dynamicPaint_findNeighbourPixel() return codes */
|
|
|
|
#define NOT_FOUND -1
|
|
|
|
#define ON_MESH_EDGE -2
|
|
|
|
#define OUT_OF_TEXTURE -3
|
2011-10-13 20:00:22 +00:00
|
|
|
/* paint effect default movement per frame in global units */
|
|
|
|
#define EFF_MOVEMENT_PER_FRAME 0.05f
|
|
|
|
/* initial wave time factor */
|
2012-05-12 16:11:34 +00:00
|
|
|
#define WAVE_TIME_FAC (1.0f / 24.f)
|
2012-01-16 17:18:07 +00:00
|
|
|
#define CANVAS_REL_SIZE 5.0f
|
2011-10-31 13:01:06 +00:00
|
|
|
/* drying limits */
|
|
|
|
#define MIN_WETNESS 0.001f
|
2012-01-16 17:18:07 +00:00
|
|
|
#define MAX_WETNESS 5.0f
|
2012-11-04 06:21:09 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* dissolve inline function */
|
|
|
|
BLI_INLINE void value_dissolve(float *r_value, const float time, const float scale, const int is_log)
|
|
|
|
{
|
|
|
|
*r_value = (is_log) ?
|
|
|
|
(*r_value) * (powf(MIN_WETNESS, 1.0f / (1.2f * time / scale))) :
|
|
|
|
(*r_value) - 1.0f / time * scale;
|
|
|
|
}
|
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
|
|
|
|
/***************************** Internal Structs ***************************/
|
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
typedef struct Bounds2D {
|
2011-06-16 10:41:00 +00:00
|
|
|
float min[2], max[2];
|
2011-07-22 18:37:30 +00:00
|
|
|
} Bounds2D;
|
|
|
|
|
|
|
|
typedef struct Bounds3D {
|
2011-09-05 16:04:15 +00:00
|
|
|
int valid;
|
2011-07-22 18:37:30 +00:00
|
|
|
float min[3], max[3];
|
|
|
|
} Bounds3D;
|
|
|
|
|
|
|
|
typedef struct VolumeGrid {
|
2011-10-13 20:00:22 +00:00
|
|
|
int dim[3];
|
2011-08-21 19:03:47 +00:00
|
|
|
Bounds3D grid_bounds; /* whole grid bounds */
|
2011-07-22 18:37:30 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
Bounds3D *bounds; /* (x*y*z) precalculated grid cell bounds */
|
2011-11-10 13:00:27 +00:00
|
|
|
int *s_pos; /* (x*y*z) t_index begin id */
|
|
|
|
int *s_num; /* (x*y*z) number of t_index points */
|
|
|
|
int *t_index; /* actual surface point index,
|
2012-05-16 23:37:23 +00:00
|
|
|
* access: (s_pos+s_num) */
|
2011-07-22 18:37:30 +00:00
|
|
|
} VolumeGrid;
|
2011-06-16 10:41:00 +00:00
|
|
|
|
|
|
|
typedef struct Vec3f {
|
|
|
|
float v[3];
|
|
|
|
} Vec3f;
|
|
|
|
|
2012-01-24 17:28:50 +00:00
|
|
|
typedef struct BakeAdjPoint {
|
2012-05-12 16:11:34 +00:00
|
|
|
float dir[3]; /* vector pointing towards this neighbor */
|
|
|
|
float dist; /* distance to */
|
2012-01-24 17:28:50 +00:00
|
|
|
} BakeAdjPoint;
|
2011-07-22 18:37:30 +00:00
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/* Surface data used while processing a frame */
|
2011-07-22 18:37:30 +00:00
|
|
|
typedef struct PaintBakeNormal {
|
|
|
|
float invNorm[3]; /* current pixel world-space inverted normal */
|
2011-06-16 10:41:00 +00:00
|
|
|
float normal_scale; /* normal directional scale for displace mapping */
|
2011-07-22 18:37:30 +00:00
|
|
|
} PaintBakeNormal;
|
2011-06-16 10:41:00 +00:00
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
/* Temp surface data used to process a frame */
|
2011-06-17 18:04:56 +00:00
|
|
|
typedef struct PaintBakeData {
|
2011-08-03 18:31:48 +00:00
|
|
|
/* point space data */
|
2011-07-22 18:37:30 +00:00
|
|
|
PaintBakeNormal *bNormal;
|
2012-05-12 16:11:34 +00:00
|
|
|
int *s_pos; /* index to start reading point sample realCoord */
|
|
|
|
int *s_num; /* num of realCoord samples */
|
2011-08-21 19:03:47 +00:00
|
|
|
Vec3f *realCoord; /* current pixel center world-space coordinates for each sample
|
2012-03-09 18:28:30 +00:00
|
|
|
* ordered as (s_pos+s_num)*/
|
2011-11-16 18:32:28 +00:00
|
|
|
Bounds3D mesh_bounds;
|
2011-07-22 18:37:30 +00:00
|
|
|
|
2011-08-21 19:03:47 +00:00
|
|
|
/* adjacency info */
|
2012-03-01 12:20:18 +00:00
|
|
|
BakeAdjPoint *bNeighs; /* current global neighbor distances and directions, if required */
|
2011-08-03 18:31:48 +00:00
|
|
|
double average_dist;
|
|
|
|
/* space partitioning */
|
2012-05-12 16:11:34 +00:00
|
|
|
VolumeGrid *grid; /* space partitioning grid to optimize brush checks */
|
2011-07-22 18:37:30 +00:00
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
/* velocity and movement */
|
2012-05-12 16:11:34 +00:00
|
|
|
Vec3f *velocity; /* speed vector in global space movement per frame, if required */
|
2011-08-03 18:31:48 +00:00
|
|
|
Vec3f *prev_velocity;
|
2012-05-12 16:11:34 +00:00
|
|
|
float *brush_velocity; /* special temp data for post-p velocity based brushes like smudge
|
|
|
|
* 3 float dir vec + 1 float str */
|
|
|
|
MVert *prev_verts; /* copy of previous frame vertices. used to observe surface movement */
|
2011-07-22 18:37:30 +00:00
|
|
|
float prev_obmat[4][4]; /* previous frame object matrix */
|
2012-05-12 16:11:34 +00:00
|
|
|
int clear; /* flag to check if surface was cleared/reset -> have to redo velocity etc. */
|
2011-07-22 18:37:30 +00:00
|
|
|
|
2011-06-17 18:04:56 +00:00
|
|
|
} PaintBakeData;
|
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/* UV Image sequence format point */
|
2011-06-27 07:30:58 +00:00
|
|
|
typedef struct PaintUVPoint {
|
2011-06-16 10:41:00 +00:00
|
|
|
/* Pixel / mesh data */
|
2012-05-12 16:11:34 +00:00
|
|
|
unsigned int face_index, pixel_index; /* face index on domain derived mesh */
|
|
|
|
unsigned int v1, v2, v3; /* vertex indexes */
|
2011-06-16 10:41:00 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
unsigned int neighbour_pixel; /* If this pixel isn't uv mapped to any face,
|
2012-05-16 23:37:23 +00:00
|
|
|
* but it's neighboring pixel is */
|
2011-06-16 10:41:00 +00:00
|
|
|
short quad;
|
2011-06-27 07:30:58 +00:00
|
|
|
} PaintUVPoint;
|
|
|
|
|
|
|
|
typedef struct ImgSeqFormatData {
|
|
|
|
PaintUVPoint *uv_p;
|
2012-05-12 16:11:34 +00:00
|
|
|
Vec3f *barycentricWeights; /* b-weights for all pixel samples */
|
2011-06-27 07:30:58 +00:00
|
|
|
} ImgSeqFormatData;
|
|
|
|
|
2011-07-02 18:06:39 +00:00
|
|
|
/* adjacency data flags */
|
2012-05-12 16:11:34 +00:00
|
|
|
#define ADJ_ON_MESH_EDGE (1 << 0)
|
2011-07-02 18:06:39 +00:00
|
|
|
|
|
|
|
typedef struct PaintAdjData {
|
2012-05-16 23:37:23 +00:00
|
|
|
int *n_target; /* array of neighboring point indexes,
|
|
|
|
* for single sample use (n_index + neigh_num) */
|
|
|
|
int *n_index; /* index to start reading n_target for each point */
|
2012-05-12 16:11:34 +00:00
|
|
|
int *n_num; /* num of neighs for each point */
|
|
|
|
int *flags; /* vertex adjacency flags */
|
2011-11-10 13:00:27 +00:00
|
|
|
int total_targets; /* size of n_target */
|
2011-07-02 18:06:39 +00:00
|
|
|
} PaintAdjData;
|
2011-06-16 10:41:00 +00:00
|
|
|
|
|
|
|
/***************************** General Utils ******************************/
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-10-28 14:46:09 +00:00
|
|
|
/* Set canvas error string to display at the bake report */
|
2011-11-10 12:28:26 +00:00
|
|
|
static int setError(DynamicPaintCanvasSettings *canvas, const char *string)
|
2011-05-24 07:08:58 +00:00
|
|
|
{
|
2011-06-16 10:41:00 +00:00
|
|
|
/* Add error to canvas ui info label */
|
2011-11-13 13:56:40 +00:00
|
|
|
BLI_strncpy(canvas->error, string, sizeof(canvas->error));
|
2011-06-16 10:41:00 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/* 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 */
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
|
2012-05-12 16:11:34 +00:00
|
|
|
if (!surface->canvas->dm) return 0; /* invalid derived mesh */
|
2011-06-16 10:41:00 +00:00
|
|
|
return surface->canvas->dm->getNumVerts(surface->canvas->dm);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/* checks whether surface's format/type has realtime preview */
|
2011-08-21 19:03:47 +00:00
|
|
|
int dynamicPaint_surfaceHasColorPreview(DynamicPaintSurface *surface)
|
|
|
|
{
|
2012-04-28 06:31:57 +00:00
|
|
|
if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
|
|
|
|
return 0;
|
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
|
2011-07-03 14:01:57 +00:00
|
|
|
if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
|
2012-04-28 06:31:57 +00:00
|
|
|
surface->type == MOD_DPAINT_SURFACE_T_WAVE)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return 1;
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* get currently active surface (in user interface) */
|
2012-05-17 23:21:11 +00:00
|
|
|
DynamicPaintSurface *get_activeSurface(DynamicPaintCanvasSettings *canvas)
|
|
|
|
{
|
2011-06-16 10:41:00 +00:00
|
|
|
DynamicPaintSurface *surface = canvas->surfaces.first;
|
|
|
|
int i;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; surface; surface = surface->next) {
|
2012-03-24 06:18:31 +00:00
|
|
|
if (i == canvas->active_sur)
|
2011-06-16 10:41:00 +00:00
|
|
|
return surface;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
return NULL;
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/* set preview to first previewable surface */
|
2011-09-05 16:04:15 +00:00
|
|
|
void dynamicPaint_resetPreview(DynamicPaintCanvasSettings *canvas)
|
2011-05-24 07:08:58 +00:00
|
|
|
{
|
2011-06-16 10:41:00 +00:00
|
|
|
DynamicPaintSurface *surface = canvas->surfaces.first;
|
2012-05-19 13:28:19 +00:00
|
|
|
int done = FALSE;
|
2011-06-16 10:41:00 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
for (; surface; surface = surface->next) {
|
2011-07-03 14:01:57 +00:00
|
|
|
if (!done && dynamicPaint_surfaceHasColorPreview(surface)) {
|
2011-06-16 10:41:00 +00:00
|
|
|
surface->flags |= MOD_DPAINT_PREVIEW;
|
2012-05-19 13:28:19 +00:00
|
|
|
done = TRUE;
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
surface->flags &= ~MOD_DPAINT_PREVIEW;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-17 18:04:56 +00:00
|
|
|
/* set preview to defined surface */
|
2011-06-16 10:41:00 +00:00
|
|
|
static void dynamicPaint_setPreview(DynamicPaintSurface *t_surface)
|
|
|
|
{
|
|
|
|
DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
|
2012-05-12 16:11:34 +00:00
|
|
|
for (; surface; surface = surface->next) {
|
2011-06-16 10:41:00 +00:00
|
|
|
if (surface == t_surface)
|
|
|
|
surface->flags |= MOD_DPAINT_PREVIEW;
|
|
|
|
else
|
|
|
|
surface->flags &= ~MOD_DPAINT_PREVIEW;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-14 06:46:07 +00:00
|
|
|
int dynamicPaint_outputLayerExists(struct DynamicPaintSurface *surface, Object *ob, int output)
|
2011-08-03 18:31:48 +00:00
|
|
|
{
|
|
|
|
char *name;
|
|
|
|
|
2011-11-14 06:46:07 +00:00
|
|
|
if (output == 0)
|
2011-08-03 18:31:48 +00:00
|
|
|
name = surface->output_name;
|
2011-11-14 06:46:07 +00:00
|
|
|
else if (output == 1)
|
2011-08-03 18:31:48 +00:00
|
|
|
name = surface->output_name2;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
|
|
|
|
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
|
|
|
|
Mesh *me = ob->data;
|
|
|
|
return (CustomData_get_named_layer_index(&me->fdata, CD_MCOL, name) != -1);
|
|
|
|
}
|
|
|
|
else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT)
|
|
|
|
return (defgroup_name_index(ob, surface->output_name) != -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-04 19:27:51 +00:00
|
|
|
static bool surface_duplicateOutputExists(void *arg, const char *name)
|
2011-09-10 08:55:44 +00:00
|
|
|
{
|
2012-05-12 16:11:34 +00:00
|
|
|
DynamicPaintSurface *t_surface = (DynamicPaintSurface *)arg;
|
2011-09-10 08:55:44 +00:00
|
|
|
DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
|
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
for (; surface; surface = surface->next) {
|
|
|
|
if (surface != t_surface && surface->type == t_surface->type &&
|
|
|
|
surface->format == t_surface->format)
|
|
|
|
{
|
2013-03-04 19:27:51 +00:00
|
|
|
if (surface->output_name[0] != '\0' && !BLI_path_cmp(name, surface->output_name)) return true;
|
|
|
|
if (surface->output_name2[0] != '\0' && !BLI_path_cmp(name, surface->output_name2)) return true;
|
2011-09-10 08:55:44 +00:00
|
|
|
}
|
|
|
|
}
|
2013-03-04 19:27:51 +00:00
|
|
|
return false;
|
2011-09-10 08:55:44 +00:00
|
|
|
}
|
|
|
|
|
2011-11-14 16:05:44 +00:00
|
|
|
static void surface_setUniqueOutputName(DynamicPaintSurface *surface, char *basename, int output)
|
2011-09-10 08:55:44 +00:00
|
|
|
{
|
|
|
|
char name[64];
|
2011-10-28 14:46:09 +00:00
|
|
|
BLI_strncpy(name, basename, sizeof(name)); /* in case basename is surface->name use a copy */
|
2011-09-10 08:55:44 +00:00
|
|
|
if (!output)
|
|
|
|
BLI_uniquename_cb(surface_duplicateOutputExists, surface, name, '.', surface->output_name, sizeof(surface->output_name));
|
|
|
|
if (output)
|
|
|
|
BLI_uniquename_cb(surface_duplicateOutputExists, surface, name, '.', surface->output_name2, sizeof(surface->output_name2));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-04 19:27:51 +00:00
|
|
|
static bool surface_duplicateNameExists(void *arg, const char *name)
|
2011-06-16 10:41:00 +00:00
|
|
|
{
|
2012-05-12 16:11:34 +00:00
|
|
|
DynamicPaintSurface *t_surface = (DynamicPaintSurface *)arg;
|
2011-06-16 10:41:00 +00:00
|
|
|
DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
|
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
for (; surface; surface = surface->next) {
|
2013-03-04 19:27:51 +00:00
|
|
|
if (surface != t_surface && !strcmp(name, surface->name)) return true;
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
2013-03-04 19:27:51 +00:00
|
|
|
return false;
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
|
2011-11-10 12:28:26 +00:00
|
|
|
void dynamicPaintSurface_setUniqueName(DynamicPaintSurface *surface, const char *basename)
|
2011-08-21 19:03:47 +00:00
|
|
|
{
|
2011-06-16 10:41:00 +00:00
|
|
|
char name[64];
|
2011-10-28 14:46:09 +00:00
|
|
|
BLI_strncpy(name, basename, sizeof(name)); /* in case basename is surface->name use a copy */
|
2011-09-10 08:55:44 +00:00
|
|
|
BLI_uniquename_cb(surface_duplicateNameExists, surface, name, '.', surface->name, sizeof(surface->name));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* change surface data to defaults on new type */
|
|
|
|
void dynamicPaintSurface_updateType(struct DynamicPaintSurface *surface)
|
|
|
|
{
|
|
|
|
if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
|
2012-05-12 16:11:34 +00:00
|
|
|
surface->output_name[0] = '\0';
|
|
|
|
surface->output_name2[0] = '\0';
|
2011-09-10 08:55:44 +00:00
|
|
|
surface->flags |= MOD_DPAINT_ANTIALIAS;
|
2011-10-13 20:00:22 +00:00
|
|
|
surface->depth_clamp = 1.0f;
|
2011-09-10 08:55:44 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-01-11 12:33:51 +00:00
|
|
|
strcpy(surface->output_name, "dp_");
|
2012-12-16 08:43:05 +00:00
|
|
|
BLI_strncpy(surface->output_name2, surface->output_name, sizeof(surface->output_name2));
|
2011-09-10 08:55:44 +00:00
|
|
|
surface->flags &= ~MOD_DPAINT_ANTIALIAS;
|
2011-10-13 20:00:22 +00:00
|
|
|
surface->depth_clamp = 0.0f;
|
2011-09-10 08:55:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
|
2012-04-29 15:47:02 +00:00
|
|
|
strcat(surface->output_name, "paintmap");
|
|
|
|
strcat(surface->output_name2, "wetmap");
|
2011-09-10 08:55:44 +00:00
|
|
|
surface_setUniqueOutputName(surface, surface->output_name2, 1);
|
|
|
|
}
|
|
|
|
else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
|
2012-04-29 15:47:02 +00:00
|
|
|
strcat(surface->output_name, "displace");
|
2011-09-10 08:55:44 +00:00
|
|
|
}
|
|
|
|
else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
|
2012-04-29 15:47:02 +00:00
|
|
|
strcat(surface->output_name, "weight");
|
2011-09-10 08:55:44 +00:00
|
|
|
}
|
|
|
|
else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
|
2012-04-29 15:47:02 +00:00
|
|
|
strcat(surface->output_name, "wave");
|
2011-09-10 08:55:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
surface_setUniqueOutputName(surface, surface->output_name, 0);
|
|
|
|
|
|
|
|
/* update preview */
|
|
|
|
if (dynamicPaint_surfaceHasColorPreview(surface))
|
|
|
|
dynamicPaint_setPreview(surface);
|
|
|
|
else
|
|
|
|
dynamicPaint_resetPreview(surface->canvas);
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
static int surface_totalSamples(DynamicPaintSurface *surface)
|
|
|
|
{
|
|
|
|
if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ &&
|
2012-04-28 06:31:57 +00:00
|
|
|
surface->flags & MOD_DPAINT_ANTIALIAS)
|
|
|
|
{
|
|
|
|
return (surface->data->total_points * 5);
|
|
|
|
}
|
2011-07-22 18:37:30 +00:00
|
|
|
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX &&
|
2012-04-28 06:31:57 +00:00
|
|
|
surface->flags & MOD_DPAINT_ANTIALIAS && surface->data->adj_data)
|
|
|
|
{
|
2012-05-12 16:11:34 +00:00
|
|
|
return (surface->data->total_points + surface->data->adj_data->total_targets);
|
2012-04-28 06:31:57 +00:00
|
|
|
}
|
2011-07-22 18:37:30 +00:00
|
|
|
|
|
|
|
return surface->data->total_points;
|
|
|
|
}
|
|
|
|
|
2012-05-12 22:13:38 +00:00
|
|
|
static void blendColors(const float t_color[3], float t_alpha, const float s_color[3], float s_alpha, float result[4])
|
2011-10-31 13:01:06 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
float i_alpha = 1.0f - s_alpha;
|
2012-05-12 16:11:34 +00:00
|
|
|
float f_alpha = t_alpha * i_alpha + s_alpha;
|
2011-10-31 13:01:06 +00:00
|
|
|
|
|
|
|
/* blend colors */
|
|
|
|
if (f_alpha) {
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
result[i] = (t_color[i] * t_alpha * i_alpha + s_color[i] * s_alpha) / f_alpha;
|
2011-10-31 13:01:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
copy_v3_v3(result, t_color);
|
|
|
|
}
|
|
|
|
/* return final alpha */
|
|
|
|
result[3] = f_alpha;
|
|
|
|
}
|
|
|
|
|
2012-01-16 17:18:07 +00:00
|
|
|
/* Mix two alpha weighed colors by a defined ratio. output is saved at a_color */
|
|
|
|
static float mixColors(float a_color[3], float a_weight, float b_color[3], float b_weight, float ratio)
|
2011-06-27 07:30:58 +00:00
|
|
|
{
|
2012-01-16 17:18:07 +00:00
|
|
|
float weight_ratio, factor;
|
|
|
|
if (b_weight) {
|
|
|
|
/* if first value has no weight just use b_color */
|
|
|
|
if (!a_weight) {
|
|
|
|
copy_v3_v3(a_color, b_color);
|
2012-05-12 16:11:34 +00:00
|
|
|
return b_weight * ratio;
|
2012-01-16 17:18:07 +00:00
|
|
|
}
|
2012-05-12 16:11:34 +00:00
|
|
|
weight_ratio = b_weight / (a_weight + b_weight);
|
2012-01-16 17:18:07 +00:00
|
|
|
}
|
2013-03-09 03:46:30 +00:00
|
|
|
else {
|
|
|
|
return a_weight * (1.0f - ratio);
|
|
|
|
}
|
2011-07-22 18:37:30 +00:00
|
|
|
|
2012-01-16 17:18:07 +00:00
|
|
|
/* calculate final interpolation factor */
|
2012-05-12 16:11:34 +00:00
|
|
|
if (ratio <= 0.5f) {
|
|
|
|
factor = weight_ratio * (ratio * 2.0f);
|
2012-01-16 17:18:07 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-05-12 16:11:34 +00:00
|
|
|
ratio = (ratio * 2.0f - 1.0f);
|
|
|
|
factor = weight_ratio * (1.0f - ratio) + ratio;
|
2012-01-16 17:18:07 +00:00
|
|
|
}
|
2011-06-27 07:30:58 +00:00
|
|
|
/* mix final color */
|
2012-01-16 17:18:07 +00:00
|
|
|
interp_v3_v3v3(a_color, a_color, b_color, factor);
|
2012-05-12 16:11:34 +00:00
|
|
|
return (1.0f - factor) * a_weight + factor * b_weight;
|
2011-06-27 07:30:58 +00:00
|
|
|
}
|
|
|
|
|
2011-08-28 16:36:47 +00:00
|
|
|
/* set "ignore cache" flag for all caches on this object */
|
|
|
|
static void object_cacheIgnoreClear(Object *ob, int state)
|
|
|
|
{
|
|
|
|
ListBase pidlist;
|
|
|
|
PTCacheID *pid;
|
|
|
|
BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
|
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
for (pid = pidlist.first; pid; pid = pid->next) {
|
2012-03-24 06:18:31 +00:00
|
|
|
if (pid->cache) {
|
2011-08-28 16:36:47 +00:00
|
|
|
if (state)
|
|
|
|
pid->cache->flag |= PTCACHE_IGNORE_CLEAR;
|
|
|
|
else
|
|
|
|
pid->cache->flag &= ~PTCACHE_IGNORE_CLEAR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_freelistN(&pidlist);
|
|
|
|
}
|
|
|
|
|
2013-03-22 17:08:55 +00:00
|
|
|
static int subframe_updateObject(Scene *scene, Object *ob, int flags, int parent_recursion, float frame)
|
2011-08-03 18:31:48 +00:00
|
|
|
{
|
|
|
|
DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType(ob, eModifierType_DynamicPaint);
|
2011-12-05 13:36:41 +00:00
|
|
|
bConstraint *con;
|
2011-08-03 18:31:48 +00:00
|
|
|
|
2012-03-18 07:38:51 +00:00
|
|
|
/* if other is dynamic paint canvas, don't update */
|
2011-08-03 18:31:48 +00:00
|
|
|
if (pmd && pmd->canvas)
|
2012-01-24 17:28:50 +00:00
|
|
|
return 1;
|
2011-08-03 18:31:48 +00:00
|
|
|
|
2011-12-05 13:36:41 +00:00
|
|
|
/* if object has parents, update them too */
|
2013-03-22 17:08:55 +00:00
|
|
|
if (parent_recursion) {
|
2013-03-25 02:41:30 +00:00
|
|
|
int recursion = parent_recursion - 1;
|
2012-01-24 17:28:50 +00:00
|
|
|
int is_canvas = 0;
|
2013-03-22 17:08:55 +00:00
|
|
|
if (ob->parent) is_canvas += subframe_updateObject(scene, ob->parent, 0, recursion, frame);
|
|
|
|
if (ob->track) is_canvas += subframe_updateObject(scene, ob->track, 0, recursion, frame);
|
2012-01-24 17:28:50 +00:00
|
|
|
|
|
|
|
/* skip subframe if object is parented
|
2012-05-12 16:11:34 +00:00
|
|
|
* to vertex of a dynamic paint canvas */
|
2012-01-24 17:28:50 +00:00
|
|
|
if (is_canvas && (ob->partype == PARVERT1 || ob->partype == PARVERT3))
|
|
|
|
return 0;
|
2011-12-05 13:36:41 +00:00
|
|
|
|
|
|
|
/* also update constraint targets */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (con = ob->constraints.first; con; con = con->next) {
|
2012-12-23 11:31:15 +00:00
|
|
|
bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
|
2011-12-05 13:36:41 +00:00
|
|
|
ListBase targets = {NULL, NULL};
|
|
|
|
|
|
|
|
if (cti && cti->get_constraint_targets) {
|
|
|
|
bConstraintTarget *ct;
|
|
|
|
cti->get_constraint_targets(con, &targets);
|
2012-05-12 16:11:34 +00:00
|
|
|
for (ct = targets.first; ct; ct = ct->next) {
|
2011-12-05 13:36:41 +00:00
|
|
|
if (ct->tar)
|
2013-03-22 17:08:55 +00:00
|
|
|
subframe_updateObject(scene, ct->tar, 0, recursion, frame);
|
2011-12-05 13:36:41 +00:00
|
|
|
}
|
|
|
|
/* free temp targets */
|
|
|
|
if (cti->flush_constraint_targets)
|
|
|
|
cti->flush_constraint_targets(con, &targets, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-08-03 18:31:48 +00:00
|
|
|
|
2012-03-27 00:01:35 +00:00
|
|
|
/* was originally OB_RECALC_ALL - TODO - which flags are really needed??? */
|
|
|
|
ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
|
2011-09-05 17:06:09 +00:00
|
|
|
BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, frame, ADT_RECALC_ANIM);
|
2011-08-28 16:36:47 +00:00
|
|
|
if (flags & UPDATE_MESH) {
|
|
|
|
/* ignore cache clear during subframe updates
|
2012-05-12 16:11:34 +00:00
|
|
|
* to not mess up cache validity */
|
2011-08-28 16:36:47 +00:00
|
|
|
object_cacheIgnoreClear(ob, 1);
|
2013-12-26 17:24:42 +06:00
|
|
|
BKE_object_handle_update(G.main->eval_ctx, scene, ob);
|
2011-08-28 16:36:47 +00:00
|
|
|
object_cacheIgnoreClear(ob, 0);
|
|
|
|
}
|
2011-08-03 18:31:48 +00:00
|
|
|
else
|
2012-05-05 14:03:12 +00:00
|
|
|
BKE_object_where_is_calc_time(scene, ob, frame);
|
2012-01-24 17:28:50 +00:00
|
|
|
|
2012-06-29 11:19:29 +00:00
|
|
|
/* for curve following objects, parented curve has to be updated too */
|
|
|
|
if (ob->type == OB_CURVE) {
|
|
|
|
Curve *cu = ob->data;
|
|
|
|
BKE_animsys_evaluate_animdata(scene, &cu->id, cu->adt, frame, ADT_RECALC_ANIM);
|
|
|
|
}
|
|
|
|
/* and armatures... */
|
|
|
|
if (ob->type == OB_ARMATURE) {
|
|
|
|
bArmature *arm = ob->data;
|
|
|
|
BKE_animsys_evaluate_animdata(scene, &arm->id, arm->adt, frame, ADT_RECALC_ANIM);
|
|
|
|
BKE_pose_where_is(scene, ob);
|
|
|
|
}
|
|
|
|
|
2012-01-24 17:28:50 +00:00
|
|
|
return 0;
|
2011-08-03 18:31:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2011-11-10 13:00:27 +00:00
|
|
|
static int surface_getBrushFlags(DynamicPaintSurface *surface, Scene *scene)
|
2011-08-03 18:31:48 +00:00
|
|
|
{
|
|
|
|
Base *base = NULL;
|
2012-10-21 05:46:41 +00:00
|
|
|
GroupObject *go = NULL;
|
2011-08-03 18:31:48 +00:00
|
|
|
Object *brushObj = NULL;
|
|
|
|
ModifierData *md = NULL;
|
|
|
|
|
|
|
|
int flags = 0;
|
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
if (surface->brush_group)
|
2011-08-03 18:31:48 +00:00
|
|
|
go = surface->brush_group->gobject.first;
|
|
|
|
else
|
|
|
|
base = scene->base.first;
|
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
while (base || go) {
|
2011-08-03 18:31:48 +00:00
|
|
|
brushObj = NULL;
|
|
|
|
|
|
|
|
/* select object */
|
2012-05-19 13:55:54 +00:00
|
|
|
if (surface->brush_group) {
|
2012-05-12 16:11:34 +00:00
|
|
|
if (go->ob) brushObj = go->ob;
|
2012-05-19 13:55:54 +00:00
|
|
|
}
|
|
|
|
else
|
2011-08-03 18:31:48 +00:00
|
|
|
brushObj = base->object;
|
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
if (!brushObj) {
|
2012-03-24 06:18:31 +00:00
|
|
|
if (surface->brush_group) go = go->next;
|
2012-05-12 16:11:34 +00:00
|
|
|
else base = base->next;
|
2012-05-19 13:55:54 +00:00
|
|
|
continue;
|
2011-08-03 18:31:48 +00:00
|
|
|
}
|
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
if (surface->brush_group)
|
2011-08-03 18:31:48 +00:00
|
|
|
go = go->next;
|
|
|
|
else
|
2012-05-12 16:11:34 +00:00
|
|
|
base = base->next;
|
2011-08-03 18:31:48 +00:00
|
|
|
|
|
|
|
md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
|
2012-04-28 06:31:57 +00:00
|
|
|
if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
|
2011-08-03 18:31:48 +00:00
|
|
|
DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md;
|
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
if (pmd2->brush) {
|
2011-08-03 18:31:48 +00:00
|
|
|
DynamicPaintBrushSettings *brush = pmd2->brush;
|
|
|
|
|
|
|
|
if (brush->flags & MOD_DPAINT_USES_VELOCITY)
|
|
|
|
flags |= BRUSH_USES_VELOCITY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return flags;
|
|
|
|
}
|
|
|
|
|
2011-11-09 15:46:53 +00:00
|
|
|
static int brush_usesMaterial(DynamicPaintBrushSettings *brush, Scene *scene)
|
|
|
|
{
|
|
|
|
return ((brush->flags & MOD_DPAINT_USE_MATERIAL) && (!strcmp(scene->r.engine, "BLENDER_RENDER")));
|
|
|
|
}
|
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* check whether two bounds intersect */
|
2011-07-22 18:37:30 +00:00
|
|
|
static int boundsIntersect(Bounds3D *b1, Bounds3D *b2)
|
|
|
|
{
|
2012-05-12 16:11:34 +00:00
|
|
|
int i = 2;
|
2011-09-05 16:04:15 +00:00
|
|
|
if (!b1->valid || !b2->valid) return 0;
|
2012-05-12 16:11:34 +00:00
|
|
|
for (; i >= 0; i -= 1)
|
2011-07-22 18:37:30 +00:00
|
|
|
if (!(b1->min[i] <= b2->max[i] && b1->max[i] >= b2->min[i])) return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* check whether two bounds intersect inside defined proximity */
|
2011-07-22 18:37:30 +00:00
|
|
|
static int boundsIntersectDist(Bounds3D *b1, Bounds3D *b2, float dist)
|
|
|
|
{
|
2012-05-12 16:11:34 +00:00
|
|
|
int i = 2;
|
2011-09-05 16:04:15 +00:00
|
|
|
if (!b1->valid || !b2->valid) return 0;
|
2012-05-12 16:11:34 +00:00
|
|
|
for (; i >= 0; i -= 1)
|
|
|
|
if (!(b1->min[i] <= (b2->max[i] + dist) && b1->max[i] >= (b2->min[i] - dist))) return 0;
|
2011-07-22 18:37:30 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* check whether bounds intersects a point with given radius */
|
2011-07-22 18:37:30 +00:00
|
|
|
static int boundIntersectPoint(Bounds3D *b, float point[3], float radius)
|
|
|
|
{
|
2012-05-12 16:11:34 +00:00
|
|
|
int i = 2;
|
2011-09-05 16:04:15 +00:00
|
|
|
if (!b->valid) return 0;
|
2012-05-12 16:11:34 +00:00
|
|
|
for (; i >= 0; i -= 1)
|
|
|
|
if (!(b->min[i] <= (point[i] + radius) && b->max[i] >= (point[i] - radius))) return 0;
|
2011-07-22 18:37:30 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* expand bounds by a new point */
|
2011-07-22 18:37:30 +00:00
|
|
|
static void boundInsert(Bounds3D *b, float point[3])
|
|
|
|
{
|
2012-05-12 16:11:34 +00:00
|
|
|
int i = 2;
|
2011-09-05 16:04:15 +00:00
|
|
|
if (!b->valid) {
|
2011-10-28 14:46:09 +00:00
|
|
|
copy_v3_v3(b->min, point);
|
|
|
|
copy_v3_v3(b->max, point);
|
2011-09-05 16:04:15 +00:00
|
|
|
b->valid = 1;
|
|
|
|
}
|
|
|
|
else {
|
2012-05-12 16:11:34 +00:00
|
|
|
for (; i >= 0; i -= 1) {
|
|
|
|
if (point[i] < b->min[i]) b->min[i] = point[i];
|
|
|
|
if (point[i] > b->max[i]) b->max[i] = point[i];
|
2011-09-05 16:04:15 +00:00
|
|
|
}
|
2011-07-22 18:37:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-15 01:52:28 +00:00
|
|
|
static float getSurfaceDimension(PaintSurfaceData *sData)
|
2012-01-16 17:18:07 +00:00
|
|
|
{
|
|
|
|
Bounds3D *mb = &sData->bData->mesh_bounds;
|
2012-12-21 05:07:26 +00:00
|
|
|
return max_fff((mb->max[0] - mb->min[0]), (mb->max[1] - mb->min[1]), (mb->max[2] - mb->min[2]));
|
2012-01-16 17:18:07 +00:00
|
|
|
}
|
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
static void freeGrid(PaintSurfaceData *data)
|
|
|
|
{
|
|
|
|
PaintBakeData *bData = data->bData;
|
|
|
|
VolumeGrid *grid = bData->grid;
|
|
|
|
|
|
|
|
if (grid->bounds) MEM_freeN(grid->bounds);
|
|
|
|
if (grid->s_pos) MEM_freeN(grid->s_pos);
|
|
|
|
if (grid->s_num) MEM_freeN(grid->s_num);
|
|
|
|
if (grid->t_index) MEM_freeN(grid->t_index);
|
|
|
|
|
|
|
|
MEM_freeN(bData->grid);
|
|
|
|
bData->grid = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
|
|
|
|
{
|
|
|
|
PaintSurfaceData *sData = surface->data;
|
|
|
|
PaintBakeData *bData = sData->bData;
|
|
|
|
Bounds3D *grid_bounds;
|
|
|
|
VolumeGrid *grid;
|
|
|
|
int grid_cells, axis = 3;
|
|
|
|
int *temp_t_index = NULL;
|
|
|
|
int *temp_s_num = NULL;
|
|
|
|
|
|
|
|
#ifdef _OPENMP
|
|
|
|
int num_of_threads = omp_get_max_threads();
|
|
|
|
#else
|
|
|
|
int num_of_threads = 1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (bData->grid)
|
|
|
|
freeGrid(sData);
|
|
|
|
|
|
|
|
/* allocate separate bounds for each thread */
|
2012-05-12 16:11:34 +00:00
|
|
|
grid_bounds = MEM_callocN(sizeof(Bounds3D) * num_of_threads, "Grid Bounds");
|
2011-07-22 18:37:30 +00:00
|
|
|
bData->grid = MEM_callocN(sizeof(VolumeGrid), "Surface Grid");
|
|
|
|
grid = bData->grid;
|
|
|
|
|
|
|
|
if (grid && grid_bounds) {
|
2011-10-13 20:00:22 +00:00
|
|
|
int i, error = 0;
|
2011-07-22 18:37:30 +00:00
|
|
|
float dim_factor, volume, dim[3];
|
2011-10-13 20:00:22 +00:00
|
|
|
float td[3];
|
2011-08-03 18:31:48 +00:00
|
|
|
float min_dim;
|
2011-07-22 18:37:30 +00:00
|
|
|
|
|
|
|
/* calculate canvas dimensions */
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < sData->total_points; i++) {
|
2013-12-22 14:11:10 +11:00
|
|
|
#ifdef _OPENMP
|
2011-07-22 18:37:30 +00:00
|
|
|
int id = omp_get_thread_num();
|
2011-10-13 20:00:22 +00:00
|
|
|
boundInsert(&grid_bounds[id], (bData->realCoord[bData->s_pos[i]].v));
|
2013-12-22 14:11:10 +11:00
|
|
|
#else
|
2011-10-13 20:00:22 +00:00
|
|
|
boundInsert(&grid_bounds[0], (bData->realCoord[bData->s_pos[i]].v));
|
2013-12-22 14:11:10 +11:00
|
|
|
#endif
|
2011-07-22 18:37:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* get final dimensions */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < num_of_threads; i++) {
|
2011-10-13 20:00:22 +00:00
|
|
|
boundInsert(&grid->grid_bounds, grid_bounds[i].min);
|
|
|
|
boundInsert(&grid->grid_bounds, grid_bounds[i].max);
|
2011-07-22 18:37:30 +00:00
|
|
|
}
|
|
|
|
|
2011-10-13 20:00:22 +00:00
|
|
|
/* get dimensions */
|
|
|
|
sub_v3_v3v3(dim, grid->grid_bounds.max, grid->grid_bounds.min);
|
|
|
|
copy_v3_v3(td, dim);
|
2012-12-21 05:07:26 +00:00
|
|
|
min_dim = max_fff(td[0], td[1], td[2]) / 1000.f;
|
2011-07-22 18:37:30 +00:00
|
|
|
|
|
|
|
/* deactivate zero axises */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < 3; i++) {
|
2012-06-25 07:24:48 +00:00
|
|
|
if (td[i] < min_dim) { td[i] = 1.0f; axis -= 1; }
|
2011-10-13 20:00:22 +00:00
|
|
|
}
|
2011-07-22 18:37:30 +00:00
|
|
|
|
2012-12-21 05:07:26 +00:00
|
|
|
if (axis == 0 || max_fff(td[0], td[1], td[2]) < 0.0001f) {
|
2011-10-13 20:00:22 +00:00
|
|
|
MEM_freeN(grid_bounds);
|
|
|
|
MEM_freeN(bData->grid);
|
|
|
|
bData->grid = NULL;
|
2011-07-22 18:37:30 +00:00
|
|
|
return;
|
2011-10-13 20:00:22 +00:00
|
|
|
}
|
2011-07-22 18:37:30 +00:00
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
/* now calculate grid volume/area/width depending on num of active axis */
|
2012-05-12 16:11:34 +00:00
|
|
|
volume = td[0] * td[1] * td[2];
|
2011-07-22 18:37:30 +00:00
|
|
|
|
|
|
|
/* determine final grid size by trying to fit average 10.000 points per grid cell */
|
2012-11-04 06:21:09 +00:00
|
|
|
dim_factor = (float)pow((double)volume / ((double)sData->total_points / 10000.0), 1.0 / (double)axis);
|
2011-07-22 18:37:30 +00:00
|
|
|
|
|
|
|
/* define final grid size using dim_factor, use min 3 for active axises */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < 3; i++) {
|
2011-10-13 20:00:22 +00:00
|
|
|
grid->dim[i] = (int)floor(td[i] / dim_factor);
|
2012-05-12 16:11:34 +00:00
|
|
|
CLAMP(grid->dim[i], (dim[i] >= min_dim) ? 3 : 1, 100);
|
2011-10-13 20:00:22 +00:00
|
|
|
}
|
2012-05-12 16:11:34 +00:00
|
|
|
grid_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
|
2011-07-22 18:37:30 +00:00
|
|
|
|
|
|
|
/* allocate memory for grids */
|
|
|
|
grid->bounds = MEM_callocN(sizeof(Bounds3D) * grid_cells, "Surface Grid Bounds");
|
|
|
|
grid->s_pos = MEM_callocN(sizeof(int) * grid_cells, "Surface Grid Position");
|
2012-05-12 16:11:34 +00:00
|
|
|
grid->s_num = MEM_callocN(sizeof(int) * grid_cells * num_of_threads, "Surface Grid Points");
|
2011-07-22 18:37:30 +00:00
|
|
|
temp_s_num = MEM_callocN(sizeof(int) * grid_cells, "Temp Surface Grid Points");
|
|
|
|
grid->t_index = MEM_callocN(sizeof(int) * sData->total_points, "Surface Grid Target Ids");
|
|
|
|
temp_t_index = MEM_callocN(sizeof(int) * sData->total_points, "Temp Surface Grid Target Ids");
|
|
|
|
|
2012-03-04 04:35:12 +00:00
|
|
|
/* in case of an allocation failure abort here */
|
2011-07-22 18:37:30 +00:00
|
|
|
if (!grid->bounds || !grid->s_pos || !grid->s_num || !grid->t_index || !temp_s_num || !temp_t_index)
|
|
|
|
error = 1;
|
|
|
|
|
|
|
|
if (!error) {
|
|
|
|
/* calculate number of points withing each cell */
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < sData->total_points; i++) {
|
2011-10-13 20:00:22 +00:00
|
|
|
int co[3], j;
|
2012-05-12 16:11:34 +00:00
|
|
|
for (j = 0; j < 3; j++) {
|
|
|
|
co[j] = (int)floor((bData->realCoord[bData->s_pos[i]].v[j] - grid->grid_bounds.min[j]) / dim[j] * grid->dim[j]);
|
|
|
|
CLAMP(co[j], 0, grid->dim[j] - 1);
|
2011-10-13 20:00:22 +00:00
|
|
|
}
|
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
temp_t_index[i] = co[0] + co[1] * grid->dim[0] + co[2] * grid->dim[0] * grid->dim[1];
|
2013-12-22 14:11:10 +11:00
|
|
|
#ifdef _OPENMP
|
2012-05-12 16:11:34 +00:00
|
|
|
grid->s_num[temp_t_index[i] + omp_get_thread_num() * grid_cells]++;
|
2013-12-22 14:11:10 +11:00
|
|
|
#else
|
2011-10-13 20:00:22 +00:00
|
|
|
grid->s_num[temp_t_index[i]]++;
|
2013-12-22 14:11:10 +11:00
|
|
|
#endif
|
2011-07-22 18:37:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* for first cell only calc s_num */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 1; i < num_of_threads; i++) {
|
|
|
|
grid->s_num[0] += grid->s_num[i * grid_cells];
|
2011-07-22 18:37:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* calculate grid indexes */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 1; i < grid_cells; i++) {
|
2011-07-22 18:37:30 +00:00
|
|
|
int id;
|
2012-05-12 16:11:34 +00:00
|
|
|
for (id = 1; id < num_of_threads; id++) {
|
|
|
|
grid->s_num[i] += grid->s_num[i + id * grid_cells];
|
2011-07-22 18:37:30 +00:00
|
|
|
}
|
2012-05-12 16:11:34 +00:00
|
|
|
grid->s_pos[i] = grid->s_pos[i - 1] + grid->s_num[i - 1];
|
2011-07-22 18:37:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* save point indexes to final array */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < sData->total_points; i++) {
|
2011-10-13 20:00:22 +00:00
|
|
|
int pos = grid->s_pos[temp_t_index[i]] + temp_s_num[temp_t_index[i]];
|
|
|
|
grid->t_index[pos] = i;
|
2011-07-22 18:37:30 +00:00
|
|
|
|
2011-10-13 20:00:22 +00:00
|
|
|
temp_s_num[temp_t_index[i]]++;
|
2011-07-22 18:37:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* calculate cell bounds */
|
|
|
|
{
|
|
|
|
int x;
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-05-12 16:11:34 +00:00
|
|
|
for (x = 0; x < grid->dim[0]; x++) {
|
2011-07-22 18:37:30 +00:00
|
|
|
int y;
|
2012-05-12 16:11:34 +00:00
|
|
|
for (y = 0; y < grid->dim[1]; y++) {
|
2011-07-22 18:37:30 +00:00
|
|
|
int z;
|
2012-05-12 16:11:34 +00:00
|
|
|
for (z = 0; z < grid->dim[2]; z++) {
|
|
|
|
int j, b_index = x + y * grid->dim[0] + z * grid->dim[0] * grid->dim[1];
|
2011-07-22 18:37:30 +00:00
|
|
|
/* set bounds */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (j = 0; j < 3; j++) {
|
|
|
|
int s = (j == 0) ? x : ((j == 1) ? y : z);
|
|
|
|
grid->bounds[b_index].min[j] = grid->grid_bounds.min[j] + dim[j] / grid->dim[j] * s;
|
|
|
|
grid->bounds[b_index].max[j] = grid->grid_bounds.min[j] + dim[j] / grid->dim[j] * (s + 1);
|
2011-10-13 20:00:22 +00:00
|
|
|
}
|
2011-09-05 16:04:15 +00:00
|
|
|
grid->bounds[b_index].valid = 1;
|
2011-07-22 18:37:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (temp_s_num) MEM_freeN(temp_s_num);
|
|
|
|
if (temp_t_index) MEM_freeN(temp_t_index);
|
|
|
|
|
|
|
|
/* free per thread s_num values */
|
|
|
|
grid->s_num = MEM_reallocN(grid->s_num, sizeof(int) * grid_cells);
|
|
|
|
|
2011-10-13 20:00:22 +00:00
|
|
|
if (error || !grid->s_num) {
|
2012-10-26 17:32:50 +00:00
|
|
|
setError(surface->canvas, N_("Not enough free memory"));
|
2011-07-22 18:37:30 +00:00
|
|
|
freeGrid(sData);
|
2011-10-13 20:00:22 +00:00
|
|
|
}
|
2011-07-22 18:37:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (grid_bounds) MEM_freeN(grid_bounds);
|
|
|
|
}
|
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/***************************** Freeing data ******************************/
|
|
|
|
|
|
|
|
/* Free brush data */
|
2011-09-05 16:04:15 +00:00
|
|
|
void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd)
|
2011-06-16 10:41:00 +00:00
|
|
|
{
|
2012-03-24 06:18:31 +00:00
|
|
|
if (pmd->brush) {
|
|
|
|
if (pmd->brush->dm)
|
2011-06-16 10:41:00 +00:00
|
|
|
pmd->brush->dm->release(pmd->brush->dm);
|
|
|
|
pmd->brush->dm = NULL;
|
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
if (pmd->brush->paint_ramp)
|
2012-05-12 16:11:34 +00:00
|
|
|
MEM_freeN(pmd->brush->paint_ramp);
|
2011-06-16 10:41:00 +00:00
|
|
|
pmd->brush->paint_ramp = NULL;
|
2012-03-24 06:18:31 +00:00
|
|
|
if (pmd->brush->vel_ramp)
|
2012-05-12 16:11:34 +00:00
|
|
|
MEM_freeN(pmd->brush->vel_ramp);
|
2011-08-03 18:31:48 +00:00
|
|
|
pmd->brush->vel_ramp = NULL;
|
2011-06-16 10:41:00 +00:00
|
|
|
|
|
|
|
MEM_freeN(pmd->brush);
|
|
|
|
pmd->brush = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-08 11:03:37 +00:00
|
|
|
static void dynamicPaint_freeAdjData(PaintSurfaceData *data)
|
2011-06-27 07:30:58 +00:00
|
|
|
{
|
2011-07-02 18:06:39 +00:00
|
|
|
if (data->adj_data) {
|
|
|
|
if (data->adj_data->n_index) MEM_freeN(data->adj_data->n_index);
|
2011-07-08 11:03:37 +00:00
|
|
|
if (data->adj_data->n_num) MEM_freeN(data->adj_data->n_num);
|
2011-07-02 18:06:39 +00:00
|
|
|
if (data->adj_data->n_target) MEM_freeN(data->adj_data->n_target);
|
|
|
|
if (data->adj_data->flags) MEM_freeN(data->adj_data->flags);
|
|
|
|
MEM_freeN(data->adj_data);
|
2011-07-08 11:03:37 +00:00
|
|
|
data->adj_data = NULL;
|
2011-06-27 07:30:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
static void free_bakeData(PaintSurfaceData *data)
|
|
|
|
{
|
|
|
|
PaintBakeData *bData = data->bData;
|
|
|
|
if (bData) {
|
|
|
|
if (bData->bNormal) MEM_freeN(bData->bNormal);
|
|
|
|
if (bData->s_pos) MEM_freeN(bData->s_pos);
|
|
|
|
if (bData->s_num) MEM_freeN(bData->s_num);
|
|
|
|
if (bData->realCoord) MEM_freeN(bData->realCoord);
|
|
|
|
if (bData->bNeighs) MEM_freeN(bData->bNeighs);
|
|
|
|
if (bData->grid) freeGrid(data);
|
|
|
|
if (bData->prev_verts) MEM_freeN(bData->prev_verts);
|
2011-08-03 18:31:48 +00:00
|
|
|
if (bData->velocity) MEM_freeN(bData->velocity);
|
|
|
|
if (bData->prev_velocity) MEM_freeN(bData->prev_velocity);
|
2011-07-22 18:37:30 +00:00
|
|
|
|
|
|
|
MEM_freeN(data->bData);
|
|
|
|
data->bData = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-21 19:03:47 +00:00
|
|
|
/* free surface data if it's not used anymore */
|
2012-09-15 01:52:28 +00:00
|
|
|
static void surface_freeUnusedData(DynamicPaintSurface *surface)
|
2011-08-21 19:03:47 +00:00
|
|
|
{
|
|
|
|
if (!surface->data) return;
|
|
|
|
|
|
|
|
/* free bakedata if not active or surface is baked */
|
|
|
|
if (!(surface->flags & MOD_DPAINT_ACTIVE) ||
|
2012-04-28 06:31:57 +00:00
|
|
|
(surface->pointcache && surface->pointcache->flag & PTCACHE_BAKED))
|
|
|
|
{
|
2011-08-21 19:03:47 +00:00
|
|
|
free_bakeData(surface->data);
|
2012-04-28 06:31:57 +00:00
|
|
|
}
|
2011-08-21 19:03:47 +00:00
|
|
|
}
|
|
|
|
|
2011-10-13 20:00:22 +00:00
|
|
|
void dynamicPaint_freeSurfaceData(DynamicPaintSurface *surface)
|
2011-06-16 10:41:00 +00:00
|
|
|
{
|
|
|
|
PaintSurfaceData *data = surface->data;
|
|
|
|
if (!data) return;
|
2011-06-27 07:30:58 +00:00
|
|
|
if (data->format_data) {
|
|
|
|
/* format specific free */
|
|
|
|
if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
|
2012-05-12 16:11:34 +00:00
|
|
|
ImgSeqFormatData *format_data = (ImgSeqFormatData *)data->format_data;
|
2011-06-27 07:30:58 +00:00
|
|
|
if (format_data->uv_p)
|
|
|
|
MEM_freeN(format_data->uv_p);
|
|
|
|
if (format_data->barycentricWeights)
|
|
|
|
MEM_freeN(format_data->barycentricWeights);
|
|
|
|
}
|
|
|
|
MEM_freeN(data->format_data);
|
|
|
|
}
|
2011-07-22 18:37:30 +00:00
|
|
|
/* type data */
|
2011-06-16 10:41:00 +00:00
|
|
|
if (data->type_data) MEM_freeN(data->type_data);
|
2011-07-08 11:03:37 +00:00
|
|
|
dynamicPaint_freeAdjData(data);
|
2011-07-22 18:37:30 +00:00
|
|
|
/* bake data */
|
|
|
|
free_bakeData(data);
|
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
MEM_freeN(surface->data);
|
|
|
|
surface->data = NULL;
|
|
|
|
}
|
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
void dynamicPaint_freeSurface(DynamicPaintSurface *surface)
|
2011-06-16 10:41:00 +00:00
|
|
|
{
|
|
|
|
/* point cache */
|
|
|
|
BKE_ptcache_free_list(&(surface->ptcaches));
|
|
|
|
surface->pointcache = NULL;
|
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
if (surface->effector_weights)
|
2011-06-27 07:30:58 +00:00
|
|
|
MEM_freeN(surface->effector_weights);
|
|
|
|
surface->effector_weights = NULL;
|
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
BLI_remlink(&(surface->canvas->surfaces), surface);
|
|
|
|
dynamicPaint_freeSurfaceData(surface);
|
|
|
|
MEM_freeN(surface);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Free canvas data */
|
2011-09-05 16:04:15 +00:00
|
|
|
void dynamicPaint_freeCanvas(DynamicPaintModifierData *pmd)
|
2011-06-16 10:41:00 +00:00
|
|
|
{
|
2012-03-24 06:18:31 +00:00
|
|
|
if (pmd->canvas) {
|
2011-06-16 10:41:00 +00:00
|
|
|
/* 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 */
|
2011-05-24 07:08:58 +00:00
|
|
|
if (pmd->canvas->dm)
|
|
|
|
pmd->canvas->dm->release(pmd->canvas->dm);
|
|
|
|
pmd->canvas->dm = NULL;
|
2011-06-16 10:41:00 +00:00
|
|
|
|
|
|
|
MEM_freeN(pmd->canvas);
|
|
|
|
pmd->canvas = NULL;
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/* Free whole dp modifier */
|
|
|
|
void dynamicPaint_Modifier_free(struct DynamicPaintModifierData *pmd)
|
2011-05-24 07:08:58 +00:00
|
|
|
{
|
2012-03-24 06:18:31 +00:00
|
|
|
if (pmd) {
|
2011-06-16 10:41:00 +00:00
|
|
|
dynamicPaint_freeCanvas(pmd);
|
|
|
|
dynamicPaint_freeBrush(pmd);
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
|
|
|
|
/***************************** Initialize and reset ******************************/
|
|
|
|
|
2011-05-24 07:08:58 +00:00
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* Creates a new surface and adds it to the list
|
|
|
|
* If scene is null, frame range of 1-250 is used
|
|
|
|
* A pointer to this surface is returned
|
|
|
|
*/
|
2012-05-17 23:21:11 +00:00
|
|
|
DynamicPaintSurface *dynamicPaint_createNewSurface(DynamicPaintCanvasSettings *canvas, Scene *scene)
|
|
|
|
{
|
2012-05-12 16:11:34 +00:00
|
|
|
DynamicPaintSurface *surface = MEM_callocN(sizeof(DynamicPaintSurface), "DynamicPaintSurface");
|
2013-03-25 08:29:06 +00:00
|
|
|
if (!surface)
|
|
|
|
return NULL;
|
2011-06-16 10:41:00 +00:00
|
|
|
|
|
|
|
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 */
|
2011-06-27 07:30:58 +00:00
|
|
|
surface->flags = MOD_DPAINT_ANTIALIAS | MOD_DPAINT_MULALPHA | MOD_DPAINT_DRY_LOG | MOD_DPAINT_DISSOLVE_LOG |
|
2012-05-12 16:11:34 +00:00
|
|
|
MOD_DPAINT_ACTIVE | MOD_DPAINT_PREVIEW | MOD_DPAINT_OUT1 | MOD_DPAINT_USE_DRYING;
|
2011-06-16 10:41:00 +00:00
|
|
|
surface->effect = 0;
|
|
|
|
surface->effect_ui = 1;
|
|
|
|
|
2011-10-31 13:01:06 +00:00
|
|
|
surface->diss_speed = 250;
|
|
|
|
surface->dry_speed = 500;
|
2012-01-16 17:18:07 +00:00
|
|
|
surface->color_dry_threshold = 1.0f;
|
2011-10-13 20:00:22 +00:00
|
|
|
surface->depth_clamp = 0.0f;
|
|
|
|
surface->disp_factor = 1.0f;
|
2011-06-16 10:41:00 +00:00
|
|
|
surface->disp_type = MOD_DPAINT_DISP_DISPLACE;
|
|
|
|
surface->image_fileformat = MOD_DPAINT_IMGFORMAT_PNG;
|
|
|
|
|
2012-01-16 17:18:07 +00:00
|
|
|
surface->influence_scale = 1.0f;
|
|
|
|
surface->radius_scale = 1.0f;
|
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
surface->init_color[0] = 1.0f;
|
|
|
|
surface->init_color[1] = 1.0f;
|
|
|
|
surface->init_color[2] = 1.0f;
|
|
|
|
surface->init_color[3] = 1.0f;
|
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
surface->image_resolution = 256;
|
2011-08-28 16:36:47 +00:00
|
|
|
surface->substeps = 0;
|
2011-07-08 11:03:37 +00:00
|
|
|
|
|
|
|
if (scene) {
|
|
|
|
surface->start_frame = scene->r.sfra;
|
|
|
|
surface->end_frame = scene->r.efra;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
surface->start_frame = 1;
|
|
|
|
surface->end_frame = 250;
|
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
|
|
|
|
surface->spread_speed = 1.0f;
|
2011-08-05 09:31:35 +00:00
|
|
|
surface->color_spread_speed = 1.0f;
|
2011-06-16 10:41:00 +00:00
|
|
|
surface->shrink_speed = 1.0f;
|
|
|
|
|
2011-11-16 18:32:28 +00:00
|
|
|
surface->wave_damping = 0.04f;
|
2011-10-31 13:01:06 +00:00
|
|
|
surface->wave_speed = 1.0f;
|
2011-07-02 18:06:39 +00:00
|
|
|
surface->wave_timescale = 1.0f;
|
2011-11-10 13:00:27 +00:00
|
|
|
surface->wave_spring = 0.20f;
|
2013-08-03 09:46:38 +00:00
|
|
|
surface->wave_smoothness = 1.0f;
|
2011-07-02 18:06:39 +00:00
|
|
|
|
2011-11-22 10:04:28 +00:00
|
|
|
modifier_path_init(surface->image_output_path, sizeof(surface->image_output_path), "cache_dynamicpaint");
|
2011-11-20 14:38:11 +00:00
|
|
|
|
2013-03-25 08:29:06 +00:00
|
|
|
/* Using ID_BRUSH i18n context, as we have no physics/dpaint one for now... */
|
|
|
|
dynamicPaintSurface_setUniqueName(surface, CTX_DATA_(BLF_I18NCONTEXT_ID_BRUSH, "Surface"));
|
2011-06-16 10:41:00 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
surface->effector_weights = BKE_add_effector_weights(NULL);
|
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
dynamicPaintSurface_updateType(surface);
|
|
|
|
|
|
|
|
BLI_addtail(&canvas->surfaces, surface);
|
|
|
|
|
|
|
|
return surface;
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* Initialize modifier data
|
|
|
|
*/
|
2011-07-08 11:03:37 +00:00
|
|
|
int dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, struct Scene *scene)
|
2011-05-24 07:08:58 +00:00
|
|
|
{
|
2012-03-24 06:18:31 +00:00
|
|
|
if (pmd) {
|
|
|
|
if (type == MOD_DYNAMICPAINT_TYPE_CANVAS) {
|
2011-10-31 13:01:06 +00:00
|
|
|
DynamicPaintCanvasSettings *canvas;
|
2012-03-24 06:18:31 +00:00
|
|
|
if (pmd->canvas)
|
2011-06-16 10:41:00 +00:00
|
|
|
dynamicPaint_freeCanvas(pmd);
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-10-31 13:01:06 +00:00
|
|
|
canvas = pmd->canvas = MEM_callocN(sizeof(DynamicPaintCanvasSettings), "DynamicPaint Canvas");
|
|
|
|
if (!canvas)
|
2011-07-08 11:03:37 +00:00
|
|
|
return 0;
|
2011-10-31 13:01:06 +00:00
|
|
|
canvas->pmd = pmd;
|
|
|
|
canvas->dm = NULL;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/* Create one surface */
|
2011-10-31 13:01:06 +00:00
|
|
|
if (!dynamicPaint_createNewSurface(canvas, scene))
|
2011-07-08 11:03:37 +00:00
|
|
|
return 0;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
|
|
|
}
|
2012-03-24 06:18:31 +00:00
|
|
|
else if (type == MOD_DYNAMICPAINT_TYPE_BRUSH) {
|
2011-10-31 13:01:06 +00:00
|
|
|
DynamicPaintBrushSettings *brush;
|
2012-03-24 06:18:31 +00:00
|
|
|
if (pmd->brush)
|
2011-06-16 10:41:00 +00:00
|
|
|
dynamicPaint_freeBrush(pmd);
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-10-31 13:01:06 +00:00
|
|
|
brush = pmd->brush = MEM_callocN(sizeof(DynamicPaintBrushSettings), "DynamicPaint Paint");
|
|
|
|
if (!brush)
|
2011-07-08 11:03:37 +00:00
|
|
|
return 0;
|
2011-10-31 13:01:06 +00:00
|
|
|
brush->pmd = pmd;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-10-31 13:01:06 +00:00
|
|
|
brush->psys = NULL;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-10-31 13:01:06 +00:00
|
|
|
brush->flags = MOD_DPAINT_ABS_ALPHA | MOD_DPAINT_RAMP_ALPHA;
|
|
|
|
brush->collision = MOD_DPAINT_COL_VOLUME;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-10-31 13:01:06 +00:00
|
|
|
brush->mat = NULL;
|
|
|
|
brush->r = 0.15f;
|
|
|
|
brush->g = 0.4f;
|
|
|
|
brush->b = 0.8f;
|
|
|
|
brush->alpha = 1.0f;
|
|
|
|
brush->wetness = 1.0f;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-10-31 13:01:06 +00:00
|
|
|
brush->paint_distance = 1.0f;
|
|
|
|
brush->proximity_falloff = MOD_DPAINT_PRFALL_SMOOTH;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-10-31 13:01:06 +00:00
|
|
|
brush->particle_radius = 0.2f;
|
|
|
|
brush->particle_smooth = 0.05f;
|
2011-07-02 18:06:39 +00:00
|
|
|
|
2011-11-16 18:32:28 +00:00
|
|
|
brush->wave_type = MOD_DPAINT_WAVEB_CHANGE;
|
2011-10-31 13:01:06 +00:00
|
|
|
brush->wave_factor = 1.0f;
|
|
|
|
brush->wave_clamp = 0.0f;
|
|
|
|
brush->smudge_strength = 0.3f;
|
|
|
|
brush->max_velocity = 1.0f;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-10-31 13:01:06 +00:00
|
|
|
brush->dm = NULL;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
/* Paint proximity falloff colorramp. */
|
2011-05-24 07:08:58 +00:00
|
|
|
{
|
|
|
|
CBData *ramp;
|
|
|
|
|
2013-03-18 18:25:05 +00:00
|
|
|
brush->paint_ramp = add_colorband(false);
|
2011-10-31 13:01:06 +00:00
|
|
|
if (!brush->paint_ramp)
|
2011-07-08 11:03:37 +00:00
|
|
|
return 0;
|
2011-10-31 13:01:06 +00:00
|
|
|
ramp = brush->paint_ramp->data;
|
2011-05-24 07:08:58 +00:00
|
|
|
/* 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;
|
2011-06-16 10:41:00 +00:00
|
|
|
pmd->brush->paint_ramp->tot = 2;
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
2011-08-03 18:31:48 +00:00
|
|
|
|
|
|
|
/* Brush velocity ramp. */
|
|
|
|
{
|
|
|
|
CBData *ramp;
|
|
|
|
|
2013-03-18 18:25:05 +00:00
|
|
|
brush->vel_ramp = add_colorband(false);
|
2011-10-31 13:01:06 +00:00
|
|
|
if (!brush->vel_ramp)
|
2011-08-03 18:31:48 +00:00
|
|
|
return 0;
|
2011-10-31 13:01:06 +00:00
|
|
|
ramp = brush->vel_ramp->data;
|
2011-08-03 18:31:48 +00:00
|
|
|
ramp[0].r = ramp[0].g = ramp[0].b = ramp[0].a = ramp[0].pos = 0.0f;
|
|
|
|
ramp[1].r = ramp[1].g = ramp[1].b = ramp[1].a = ramp[1].pos = 1.0f;
|
2011-10-31 13:01:06 +00:00
|
|
|
brush->paint_ramp->tot = 2;
|
2011-08-03 18:31:48 +00:00
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
|
|
|
}
|
2011-07-08 11:03:37 +00:00
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void dynamicPaint_Modifier_copy(struct DynamicPaintModifierData *pmd, struct DynamicPaintModifierData *tpmd)
|
|
|
|
{
|
|
|
|
/* Init modifier */
|
|
|
|
tpmd->type = pmd->type;
|
2011-07-08 11:03:37 +00:00
|
|
|
if (pmd->canvas)
|
|
|
|
dynamicPaint_createType(tpmd, MOD_DYNAMICPAINT_TYPE_CANVAS, NULL);
|
|
|
|
if (pmd->brush)
|
|
|
|
dynamicPaint_createType(tpmd, MOD_DYNAMICPAINT_TYPE_BRUSH, NULL);
|
2011-05-24 07:08:58 +00:00
|
|
|
|
|
|
|
/* Copy data */
|
|
|
|
if (tpmd->canvas) {
|
2012-12-16 19:19:45 +00:00
|
|
|
DynamicPaintSurface *surface;
|
2011-09-05 16:04:15 +00:00
|
|
|
tpmd->canvas->pmd = tpmd;
|
2012-12-16 19:19:45 +00:00
|
|
|
/* free default surface */
|
|
|
|
if (tpmd->canvas->surfaces.first)
|
|
|
|
dynamicPaint_freeSurface(tpmd->canvas->surfaces.first);
|
|
|
|
|
|
|
|
/* copy existing surfaces */
|
|
|
|
for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
|
|
|
|
DynamicPaintSurface *t_surface = dynamicPaint_createNewSurface(tpmd->canvas, NULL);
|
|
|
|
|
|
|
|
/* surface settings */
|
|
|
|
t_surface->brush_group = surface->brush_group;
|
|
|
|
MEM_freeN(t_surface->effector_weights);
|
|
|
|
t_surface->effector_weights = MEM_dupallocN(surface->effector_weights);
|
|
|
|
|
|
|
|
BLI_strncpy(t_surface->name, surface->name, sizeof(t_surface->name));
|
|
|
|
t_surface->format = surface->format;
|
|
|
|
t_surface->type = surface->type;
|
|
|
|
t_surface->disp_type = surface->disp_type;
|
|
|
|
t_surface->image_fileformat = surface->image_fileformat;
|
|
|
|
t_surface->effect_ui = surface->effect_ui;
|
|
|
|
t_surface->preview_id = surface->preview_id;
|
|
|
|
t_surface->init_color_type = surface->init_color_type;
|
|
|
|
t_surface->flags = surface->flags;
|
|
|
|
t_surface->effect = surface->effect;
|
|
|
|
|
|
|
|
t_surface->image_resolution = surface->image_resolution;
|
|
|
|
t_surface->substeps = surface->substeps;
|
|
|
|
t_surface->start_frame = surface->start_frame;
|
|
|
|
t_surface->end_frame = surface->end_frame;
|
|
|
|
|
|
|
|
copy_v4_v4(t_surface->init_color, surface->init_color);
|
|
|
|
t_surface->init_texture = surface->init_texture;
|
|
|
|
BLI_strncpy(t_surface->init_layername, surface->init_layername, sizeof(t_surface->init_layername));
|
|
|
|
|
|
|
|
t_surface->dry_speed = surface->dry_speed;
|
|
|
|
t_surface->diss_speed = surface->diss_speed;
|
|
|
|
t_surface->color_dry_threshold = surface->color_dry_threshold;
|
|
|
|
t_surface->depth_clamp = surface->depth_clamp;
|
|
|
|
t_surface->disp_factor = surface->disp_factor;
|
|
|
|
|
|
|
|
|
|
|
|
t_surface->spread_speed = surface->spread_speed;
|
|
|
|
t_surface->color_spread_speed = surface->color_spread_speed;
|
|
|
|
t_surface->shrink_speed = surface->shrink_speed;
|
|
|
|
t_surface->drip_vel = surface->drip_vel;
|
|
|
|
t_surface->drip_acc = surface->drip_acc;
|
|
|
|
|
|
|
|
t_surface->influence_scale = surface->influence_scale;
|
|
|
|
t_surface->radius_scale = surface->radius_scale;
|
|
|
|
|
|
|
|
t_surface->wave_damping = surface->wave_damping;
|
|
|
|
t_surface->wave_speed = surface->wave_speed;
|
|
|
|
t_surface->wave_timescale = surface->wave_timescale;
|
|
|
|
t_surface->wave_spring = surface->wave_spring;
|
2013-08-03 09:46:38 +00:00
|
|
|
t_surface->wave_smoothness = surface->wave_smoothness;
|
2012-12-16 19:19:45 +00:00
|
|
|
|
|
|
|
BLI_strncpy(t_surface->uvlayer_name, surface->uvlayer_name, sizeof(t_surface->uvlayer_name));
|
|
|
|
BLI_strncpy(t_surface->image_output_path, surface->image_output_path, sizeof(t_surface->image_output_path));
|
|
|
|
BLI_strncpy(t_surface->output_name, surface->output_name, sizeof(t_surface->output_name));
|
|
|
|
BLI_strncpy(t_surface->output_name2, surface->output_name2, sizeof(t_surface->output_name2));
|
|
|
|
}
|
|
|
|
dynamicPaint_resetPreview(tpmd->canvas);
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
|
|
|
else if (tpmd->brush) {
|
2011-10-31 13:01:06 +00:00
|
|
|
DynamicPaintBrushSettings *brush = pmd->brush, *t_brush = tpmd->brush;
|
|
|
|
t_brush->pmd = tpmd;
|
|
|
|
|
|
|
|
t_brush->flags = brush->flags;
|
|
|
|
t_brush->collision = brush->collision;
|
|
|
|
|
|
|
|
t_brush->mat = brush->mat;
|
|
|
|
t_brush->r = brush->r;
|
|
|
|
t_brush->g = brush->g;
|
|
|
|
t_brush->b = brush->b;
|
|
|
|
t_brush->alpha = brush->alpha;
|
|
|
|
t_brush->wetness = brush->wetness;
|
|
|
|
|
|
|
|
t_brush->particle_radius = brush->particle_radius;
|
|
|
|
t_brush->particle_smooth = brush->particle_smooth;
|
|
|
|
t_brush->paint_distance = brush->paint_distance;
|
|
|
|
t_brush->psys = brush->psys;
|
|
|
|
|
|
|
|
if (brush->paint_ramp)
|
|
|
|
memcpy(t_brush->paint_ramp, brush->paint_ramp, sizeof(ColorBand));
|
|
|
|
if (brush->vel_ramp)
|
|
|
|
memcpy(t_brush->vel_ramp, brush->vel_ramp, sizeof(ColorBand));
|
|
|
|
|
|
|
|
t_brush->proximity_falloff = brush->proximity_falloff;
|
|
|
|
t_brush->wave_type = brush->wave_type;
|
|
|
|
t_brush->ray_dir = brush->ray_dir;
|
|
|
|
|
|
|
|
t_brush->wave_factor = brush->wave_factor;
|
|
|
|
t_brush->wave_clamp = brush->wave_clamp;
|
|
|
|
t_brush->max_velocity = brush->max_velocity;
|
|
|
|
t_brush->smudge_strength = brush->smudge_strength;
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* allocates surface data depending on surface type */
|
|
|
|
static void dynamicPaint_allocateSurfaceType(DynamicPaintSurface *surface)
|
|
|
|
{
|
|
|
|
PaintSurfaceData *sData = surface->data;
|
|
|
|
|
2011-10-13 20:00:22 +00:00
|
|
|
switch (surface->type) {
|
|
|
|
case MOD_DPAINT_SURFACE_T_PAINT:
|
2012-05-12 16:11:34 +00:00
|
|
|
sData->type_data = MEM_callocN(sizeof(PaintPoint) * sData->total_points, "DynamicPaintSurface Data");
|
2011-10-13 20:00:22 +00:00
|
|
|
break;
|
|
|
|
case MOD_DPAINT_SURFACE_T_DISPLACE:
|
2012-05-12 16:11:34 +00:00
|
|
|
sData->type_data = MEM_callocN(sizeof(float) * sData->total_points, "DynamicPaintSurface DepthData");
|
2011-10-13 20:00:22 +00:00
|
|
|
break;
|
|
|
|
case MOD_DPAINT_SURFACE_T_WEIGHT:
|
2012-05-12 16:11:34 +00:00
|
|
|
sData->type_data = MEM_callocN(sizeof(float) * sData->total_points, "DynamicPaintSurface WeightData");
|
2011-10-13 20:00:22 +00:00
|
|
|
break;
|
|
|
|
case MOD_DPAINT_SURFACE_T_WAVE:
|
2012-05-12 16:11:34 +00:00
|
|
|
sData->type_data = MEM_callocN(sizeof(PaintWavePoint) * sData->total_points, "DynamicPaintSurface WaveData");
|
2011-10-13 20:00:22 +00:00
|
|
|
break;
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
|
2012-10-26 17:32:50 +00:00
|
|
|
if (sData->type_data == NULL) setError(surface->canvas, N_("Not enough free memory"));
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
|
2011-08-21 19:03:47 +00:00
|
|
|
static int surface_usesAdjDistance(DynamicPaintSurface *surface)
|
|
|
|
{
|
2011-07-08 11:03:37 +00:00
|
|
|
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && surface->effect) return 1;
|
|
|
|
if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) return 1;
|
2011-07-22 18:37:30 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-08-21 19:03:47 +00:00
|
|
|
static int surface_usesAdjData(DynamicPaintSurface *surface)
|
|
|
|
{
|
2011-07-22 18:37:30 +00:00
|
|
|
if (surface_usesAdjDistance(surface)) return 1;
|
2011-07-08 11:03:37 +00:00
|
|
|
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX &&
|
2012-04-28 06:31:57 +00:00
|
|
|
surface->flags & MOD_DPAINT_ANTIALIAS)
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return 0;
|
|
|
|
}
|
2011-07-02 18:06:39 +00:00
|
|
|
}
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2011-07-02 18:06:39 +00:00
|
|
|
/* initialize surface adjacency data */
|
2011-08-21 19:03:47 +00:00
|
|
|
static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int force_init)
|
|
|
|
{
|
2011-06-27 07:30:58 +00:00
|
|
|
PaintSurfaceData *sData = surface->data;
|
2012-01-24 18:29:01 +00:00
|
|
|
DerivedMesh *dm = surface->canvas->dm;
|
2012-01-24 17:28:50 +00:00
|
|
|
PaintAdjData *ad;
|
2011-07-02 18:06:39 +00:00
|
|
|
int *temp_data;
|
2011-06-27 07:30:58 +00:00
|
|
|
int neigh_points = 0;
|
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
if (!surface_usesAdjData(surface) && !force_init) return;
|
2011-06-27 07:30:58 +00:00
|
|
|
|
|
|
|
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
|
2012-03-09 00:41:09 +00:00
|
|
|
/* For vertex format, neighbors are connected by edges */
|
2012-05-12 16:11:34 +00:00
|
|
|
neigh_points = 2 * dm->getNumEdges(dm);
|
2011-06-27 07:30:58 +00:00
|
|
|
}
|
|
|
|
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
|
2012-05-12 16:11:34 +00:00
|
|
|
neigh_points = sData->total_points * 8;
|
2011-06-27 07:30:58 +00:00
|
|
|
|
|
|
|
if (!neigh_points) return;
|
|
|
|
|
|
|
|
/* allocate memory */
|
2012-01-24 17:28:50 +00:00
|
|
|
ad = sData->adj_data = MEM_callocN(sizeof(PaintAdjData), "Surface Adj Data");
|
|
|
|
if (!ad) return;
|
2012-05-12 16:11:34 +00:00
|
|
|
ad->n_index = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Index");
|
|
|
|
ad->n_num = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Counts");
|
|
|
|
temp_data = MEM_callocN(sizeof(int) * sData->total_points, "Temp Adj Data");
|
|
|
|
ad->n_target = MEM_callocN(sizeof(int) * neigh_points, "Surface Adj Targets");
|
|
|
|
ad->flags = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Flags");
|
2012-01-24 17:28:50 +00:00
|
|
|
ad->total_targets = neigh_points;
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2011-10-13 20:00:22 +00:00
|
|
|
/* in case of allocation error, free memory */
|
2012-01-24 17:28:50 +00:00
|
|
|
if (!ad->n_index || !ad->n_num || !ad->n_target || !temp_data) {
|
2011-07-08 11:03:37 +00:00
|
|
|
dynamicPaint_freeAdjData(sData);
|
2011-10-13 20:00:22 +00:00
|
|
|
if (temp_data) MEM_freeN(temp_data);
|
2012-10-26 17:32:50 +00:00
|
|
|
setError(surface->canvas, N_("Not enough free memory"));
|
2011-06-27 07:30:58 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
|
2011-07-02 18:06:39 +00:00
|
|
|
int i;
|
2011-06-27 07:30:58 +00:00
|
|
|
int n_pos;
|
|
|
|
|
|
|
|
/* For vertex format, count every vertex that is connected by an edge */
|
2012-01-24 18:29:01 +00:00
|
|
|
int numOfEdges = dm->getNumEdges(dm);
|
|
|
|
int numOfPolys = dm->getNumPolys(dm);
|
|
|
|
struct MEdge *edge = dm->getEdgeArray(dm);
|
|
|
|
struct MPoly *mpoly = dm->getPolyArray(dm);
|
|
|
|
struct MLoop *mloop = dm->getLoopArray(dm);
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2011-07-02 18:06:39 +00:00
|
|
|
/* count number of edges per vertex */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < numOfEdges; i++) {
|
2012-01-24 17:28:50 +00:00
|
|
|
ad->n_num[edge[i].v1]++;
|
|
|
|
ad->n_num[edge[i].v2]++;
|
2011-07-02 18:06:39 +00:00
|
|
|
|
|
|
|
temp_data[edge[i].v1]++;
|
|
|
|
temp_data[edge[i].v2]++;
|
|
|
|
}
|
|
|
|
|
2012-01-24 17:28:50 +00:00
|
|
|
/* also add number of vertices to temp_data
|
2012-05-12 16:11:34 +00:00
|
|
|
* to locate points on "mesh edge" */
|
|
|
|
for (i = 0; i < numOfPolys; i++) {
|
|
|
|
int j = 0;
|
|
|
|
for (; j < mpoly[i].totloop; j++) {
|
2012-01-24 18:29:01 +00:00
|
|
|
temp_data[mloop[mpoly[i].loopstart + j].v]++;
|
|
|
|
}
|
2011-07-02 18:06:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* now check if total number of edges+faces for
|
2012-05-12 16:11:34 +00:00
|
|
|
* each vertex is even, if not -> vertex is on mesh edge */
|
|
|
|
for (i = 0; i < sData->total_points; i++) {
|
2012-04-28 06:31:57 +00:00
|
|
|
if ((temp_data[i] % 2) ||
|
|
|
|
(temp_data[i] < 4))
|
|
|
|
{
|
2012-01-24 17:28:50 +00:00
|
|
|
ad->flags[i] |= ADJ_ON_MESH_EDGE;
|
2012-04-28 06:31:57 +00:00
|
|
|
}
|
|
|
|
|
2011-07-02 18:06:39 +00:00
|
|
|
/* reset temp data */
|
|
|
|
temp_data[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* order n_index array */
|
2011-06-27 07:30:58 +00:00
|
|
|
n_pos = 0;
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < sData->total_points; i++) {
|
2012-01-24 17:28:50 +00:00
|
|
|
ad->n_index[i] = n_pos;
|
|
|
|
n_pos += ad->n_num[i];
|
2011-07-02 18:06:39 +00:00
|
|
|
}
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2012-03-01 12:20:18 +00:00
|
|
|
/* and now add neighbor data using that info */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < numOfEdges; i++) {
|
2011-07-02 18:06:39 +00:00
|
|
|
/* first vertex */
|
|
|
|
int index = edge[i].v1;
|
2012-05-12 16:11:34 +00:00
|
|
|
n_pos = ad->n_index[index] + temp_data[index];
|
2012-01-24 17:28:50 +00:00
|
|
|
ad->n_target[n_pos] = edge[i].v2;
|
2011-07-02 18:06:39 +00:00
|
|
|
temp_data[index]++;
|
|
|
|
|
|
|
|
/* second vertex */
|
|
|
|
index = edge[i].v2;
|
2012-05-12 16:11:34 +00:00
|
|
|
n_pos = ad->n_index[index] + temp_data[index];
|
2012-01-24 17:28:50 +00:00
|
|
|
ad->n_target[n_pos] = edge[i].v1;
|
2011-07-02 18:06:39 +00:00
|
|
|
temp_data[index]++;
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
}
|
2011-06-27 07:30:58 +00:00
|
|
|
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
|
|
|
|
/* for image sequences, only allocate memory.
|
2012-05-12 16:11:34 +00:00
|
|
|
* bake initialization takes care of rest */
|
2011-06-27 07:30:58 +00:00
|
|
|
}
|
2011-07-02 18:06:39 +00:00
|
|
|
|
|
|
|
MEM_freeN(temp_data);
|
|
|
|
}
|
|
|
|
|
Fix #36058: Displace Modifier errors using a baked Image and displace baking inconsistency between 2.67/2.68RC and previous versions
This was in fact really nasty bug, caused by multitex_nodes
function using global variable R (which is a copy of current
renderer). this variable is not initialized to anything
meaningful for until first rendering (preview or final)
happened.
Since multitex_nodes might be used outside of render pipeline,
made it so whether CM is on or off as an argument to functions
multitex_ext_safe and multitex_ext. Now multitex_nodes() is
only shall be used for stuff happening from render pipeline!
Also needed to make some changes to other places, so all the
usages of texture sampling knows for the fact whether CM is
on or off.
And one more change is related on behavior of dispalcement,
wave, warp, weightvg modifiers and smoke. They'll be always
using CM off since texture is used for influence, not for
color.
It's rather bigger patch, but it's mostly straightforward
changes, which we really need to be done.
Reviewed by Brecht, thanks!
2013-07-15 14:47:58 +00:00
|
|
|
static void dynamicPaint_setInitialColor(Scene *scene, DynamicPaintSurface *surface)
|
2011-09-05 16:04:15 +00:00
|
|
|
{
|
|
|
|
PaintSurfaceData *sData = surface->data;
|
2012-05-12 16:11:34 +00:00
|
|
|
PaintPoint *pPoint = (PaintPoint *)sData->type_data;
|
2011-09-05 16:04:15 +00:00
|
|
|
DerivedMesh *dm = surface->canvas->dm;
|
|
|
|
int i;
|
Fix #36058: Displace Modifier errors using a baked Image and displace baking inconsistency between 2.67/2.68RC and previous versions
This was in fact really nasty bug, caused by multitex_nodes
function using global variable R (which is a copy of current
renderer). this variable is not initialized to anything
meaningful for until first rendering (preview or final)
happened.
Since multitex_nodes might be used outside of render pipeline,
made it so whether CM is on or off as an argument to functions
multitex_ext_safe and multitex_ext. Now multitex_nodes() is
only shall be used for stuff happening from render pipeline!
Also needed to make some changes to other places, so all the
usages of texture sampling knows for the fact whether CM is
on or off.
And one more change is related on behavior of dispalcement,
wave, warp, weightvg modifiers and smoke. They'll be always
using CM off since texture is used for influence, not for
color.
It's rather bigger patch, but it's mostly straightforward
changes, which we really need to be done.
Reviewed by Brecht, thanks!
2013-07-15 14:47:58 +00:00
|
|
|
bool scene_color_manage = BKE_scene_check_color_management_enabled(scene);
|
2011-09-05 16:04:15 +00:00
|
|
|
|
|
|
|
if (surface->type != MOD_DPAINT_SURFACE_T_PAINT)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (surface->init_color_type == MOD_DPAINT_INITIAL_NONE)
|
|
|
|
return;
|
|
|
|
/* Single color */
|
|
|
|
else if (surface->init_color_type == MOD_DPAINT_INITIAL_COLOR) {
|
|
|
|
/* apply color to every surface point */
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < sData->total_points; i++) {
|
2011-10-28 14:46:09 +00:00
|
|
|
copy_v3_v3(pPoint[i].color, surface->init_color);
|
2011-09-05 16:04:15 +00:00
|
|
|
pPoint[i].alpha = surface->init_color[3];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* UV mapped texture */
|
|
|
|
else if (surface->init_color_type == MOD_DPAINT_INITIAL_TEXTURE) {
|
|
|
|
Tex *tex = surface->init_texture;
|
|
|
|
MTFace *tface;
|
2011-11-11 11:20:46 +00:00
|
|
|
MFace *mface = dm->getTessFaceArray(dm);
|
|
|
|
int numOfFaces = dm->getNumTessFaces(dm);
|
2012-01-11 08:51:06 +00:00
|
|
|
char uvname[MAX_CUSTOMDATA_LAYER_NAME];
|
2011-09-05 16:04:15 +00:00
|
|
|
|
|
|
|
if (!tex) return;
|
|
|
|
|
2011-11-23 17:25:25 +00:00
|
|
|
/* get uv map */
|
2011-10-13 20:00:22 +00:00
|
|
|
CustomData_validate_layer_name(&dm->faceData, CD_MTFACE, surface->init_layername, uvname);
|
2011-09-05 16:04:15 +00:00
|
|
|
tface = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, uvname);
|
|
|
|
if (!tface) return;
|
|
|
|
|
|
|
|
/* for vertex surface loop through tfaces and find uv color
|
2012-05-12 16:11:34 +00:00
|
|
|
* that provides highest alpha */
|
2011-09-05 16:04:15 +00:00
|
|
|
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
|
2013-01-21 08:49:42 +00:00
|
|
|
struct ImagePool *pool = BKE_image_pool_new();
|
|
|
|
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static) shared(pool)
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < numOfFaces; i++) {
|
2011-09-05 16:04:15 +00:00
|
|
|
int numOfVert = (mface[i].v4) ? 4 : 3;
|
|
|
|
float uv[3] = {0.0f};
|
|
|
|
int j;
|
2012-05-12 16:11:34 +00:00
|
|
|
for (j = 0; j < numOfVert; j++) {
|
2011-09-05 16:04:15 +00:00
|
|
|
TexResult texres = {0};
|
2012-05-12 16:11:34 +00:00
|
|
|
unsigned int *vert = (&mface[i].v1) + j;
|
2011-09-05 16:04:15 +00:00
|
|
|
|
|
|
|
/* remap to -1.0 to 1.0 */
|
2012-05-12 16:11:34 +00:00
|
|
|
uv[0] = tface[i].uv[j][0] * 2.0f - 1.0f;
|
|
|
|
uv[1] = tface[i].uv[j][1] * 2.0f - 1.0f;
|
2011-09-05 16:04:15 +00:00
|
|
|
|
Fix #36058: Displace Modifier errors using a baked Image and displace baking inconsistency between 2.67/2.68RC and previous versions
This was in fact really nasty bug, caused by multitex_nodes
function using global variable R (which is a copy of current
renderer). this variable is not initialized to anything
meaningful for until first rendering (preview or final)
happened.
Since multitex_nodes might be used outside of render pipeline,
made it so whether CM is on or off as an argument to functions
multitex_ext_safe and multitex_ext. Now multitex_nodes() is
only shall be used for stuff happening from render pipeline!
Also needed to make some changes to other places, so all the
usages of texture sampling knows for the fact whether CM is
on or off.
And one more change is related on behavior of dispalcement,
wave, warp, weightvg modifiers and smoke. They'll be always
using CM off since texture is used for influence, not for
color.
It's rather bigger patch, but it's mostly straightforward
changes, which we really need to be done.
Reviewed by Brecht, thanks!
2013-07-15 14:47:58 +00:00
|
|
|
multitex_ext_safe(tex, uv, &texres, pool, scene_color_manage);
|
2011-09-05 16:04:15 +00:00
|
|
|
|
|
|
|
if (texres.tin > pPoint[*vert].alpha) {
|
2011-10-28 14:46:09 +00:00
|
|
|
copy_v3_v3(pPoint[*vert].color, &texres.tr);
|
2011-09-05 16:04:15 +00:00
|
|
|
pPoint[*vert].alpha = texres.tin;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-01-21 08:49:42 +00:00
|
|
|
BKE_image_pool_free(pool);
|
2011-09-05 16:04:15 +00:00
|
|
|
}
|
|
|
|
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
|
2012-05-12 16:11:34 +00:00
|
|
|
ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
|
2011-09-05 16:04:15 +00:00
|
|
|
int samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
|
|
|
|
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < sData->total_points; i++) {
|
2011-09-05 16:04:15 +00:00
|
|
|
float uv[9] = {0.0f};
|
|
|
|
float uv_final[3] = {0.0f};
|
|
|
|
int j;
|
|
|
|
TexResult texres = {0};
|
|
|
|
|
|
|
|
/* collect all uvs */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (j = 0; j < 3; j++) {
|
|
|
|
int v = (f_data->uv_p[i].quad && j > 0) ? j + 1 : j;
|
|
|
|
copy_v2_v2(&uv[j * 3], tface[f_data->uv_p[i].face_index].uv[v]);
|
2011-09-05 16:04:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* interpolate final uv pos */
|
2012-04-29 17:11:40 +00:00
|
|
|
interp_v3_v3v3v3(uv_final, &uv[0], &uv[3], &uv[6],
|
2012-05-12 16:11:34 +00:00
|
|
|
f_data->barycentricWeights[i * samples].v);
|
2011-09-05 16:04:15 +00:00
|
|
|
/* remap to -1.0 to 1.0 */
|
2012-05-12 16:11:34 +00:00
|
|
|
uv_final[0] = uv_final[0] * 2.0f - 1.0f;
|
|
|
|
uv_final[1] = uv_final[1] * 2.0f - 1.0f;
|
Fix #36058: Displace Modifier errors using a baked Image and displace baking inconsistency between 2.67/2.68RC and previous versions
This was in fact really nasty bug, caused by multitex_nodes
function using global variable R (which is a copy of current
renderer). this variable is not initialized to anything
meaningful for until first rendering (preview or final)
happened.
Since multitex_nodes might be used outside of render pipeline,
made it so whether CM is on or off as an argument to functions
multitex_ext_safe and multitex_ext. Now multitex_nodes() is
only shall be used for stuff happening from render pipeline!
Also needed to make some changes to other places, so all the
usages of texture sampling knows for the fact whether CM is
on or off.
And one more change is related on behavior of dispalcement,
wave, warp, weightvg modifiers and smoke. They'll be always
using CM off since texture is used for influence, not for
color.
It's rather bigger patch, but it's mostly straightforward
changes, which we really need to be done.
Reviewed by Brecht, thanks!
2013-07-15 14:47:58 +00:00
|
|
|
|
|
|
|
multitex_ext_safe(tex, uv_final, &texres, NULL, scene_color_manage);
|
2011-09-05 16:04:15 +00:00
|
|
|
|
|
|
|
/* apply color */
|
2011-10-28 14:46:09 +00:00
|
|
|
copy_v3_v3(pPoint[i].color, &texres.tr);
|
2011-09-05 16:04:15 +00:00
|
|
|
pPoint[i].alpha = texres.tin;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* vertex color layer */
|
|
|
|
else if (surface->init_color_type == MOD_DPAINT_INITIAL_VERTEXCOLOR) {
|
|
|
|
|
|
|
|
/* for vertex surface, just copy colors from mcol */
|
|
|
|
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
|
2012-01-24 18:29:01 +00:00
|
|
|
MLoop *mloop = dm->getLoopArray(dm);
|
|
|
|
int numOfLoops = dm->getNumLoops(dm);
|
|
|
|
MCol *col = CustomData_get_layer_named(&dm->loopData, CD_MLOOPCOL, surface->init_layername);
|
|
|
|
if (!col) return;
|
2011-09-05 16:04:15 +00:00
|
|
|
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < numOfLoops; i++) {
|
|
|
|
pPoint[mloop[i].v].color[0] = 1.0f / 255.f * (float)col[i].b;
|
|
|
|
pPoint[mloop[i].v].color[1] = 1.0f / 255.f * (float)col[i].g;
|
|
|
|
pPoint[mloop[i].v].color[2] = 1.0f / 255.f * (float)col[i].r;
|
|
|
|
pPoint[mloop[i].v].alpha = 1.0f / 255.f * (float)col[i].a;
|
2011-09-05 16:04:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
|
2012-05-12 16:11:34 +00:00
|
|
|
ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
|
2011-09-05 16:04:15 +00:00
|
|
|
int samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
|
2012-01-24 18:29:01 +00:00
|
|
|
MCol *col = CustomData_get_layer_named(&dm->faceData, CD_MCOL, surface->init_layername);
|
|
|
|
if (!col) return;
|
2011-09-05 16:04:15 +00:00
|
|
|
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < sData->total_points; i++) {
|
2011-09-05 16:04:15 +00:00
|
|
|
int face_ind = f_data->uv_p[i].face_index;
|
2012-04-29 15:47:02 +00:00
|
|
|
float colors[3][4] = {{0.0f, 0.0f, 0.0f, 0.0f}};
|
2011-09-05 16:04:15 +00:00
|
|
|
float final_color[4];
|
|
|
|
int j;
|
|
|
|
/* collect color values */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (j = 0; j < 3; j++) {
|
|
|
|
int v = (f_data->uv_p[i].quad && j > 0) ? j + 1 : j;
|
|
|
|
colors[j][0] = 1.0f / 255.f * (float)col[face_ind * 4 + v].b;
|
|
|
|
colors[j][1] = 1.0f / 255.f * (float)col[face_ind * 4 + v].g;
|
|
|
|
colors[j][2] = 1.0f / 255.f * (float)col[face_ind * 4 + v].r;
|
|
|
|
colors[j][3] = 1.0f / 255.f * (float)col[face_ind * 4 + v].a;
|
2011-09-05 16:04:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* interpolate final color */
|
2012-04-29 17:11:40 +00:00
|
|
|
interp_v4_v4v4v4(final_color, colors[0], colors[1], colors[2],
|
2012-05-12 16:11:34 +00:00
|
|
|
f_data->barycentricWeights[i * samples].v);
|
2011-09-05 16:04:15 +00:00
|
|
|
|
2011-10-28 14:46:09 +00:00
|
|
|
copy_v3_v3(pPoint[i].color, final_color);
|
2011-09-05 16:04:15 +00:00
|
|
|
pPoint[i].alpha = final_color[3];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-02 18:06:39 +00:00
|
|
|
/* clears surface data back to zero */
|
Fix #36058: Displace Modifier errors using a baked Image and displace baking inconsistency between 2.67/2.68RC and previous versions
This was in fact really nasty bug, caused by multitex_nodes
function using global variable R (which is a copy of current
renderer). this variable is not initialized to anything
meaningful for until first rendering (preview or final)
happened.
Since multitex_nodes might be used outside of render pipeline,
made it so whether CM is on or off as an argument to functions
multitex_ext_safe and multitex_ext. Now multitex_nodes() is
only shall be used for stuff happening from render pipeline!
Also needed to make some changes to other places, so all the
usages of texture sampling knows for the fact whether CM is
on or off.
And one more change is related on behavior of dispalcement,
wave, warp, weightvg modifiers and smoke. They'll be always
using CM off since texture is used for influence, not for
color.
It's rather bigger patch, but it's mostly straightforward
changes, which we really need to be done.
Reviewed by Brecht, thanks!
2013-07-15 14:47:58 +00:00
|
|
|
void dynamicPaint_clearSurface(Scene *scene, DynamicPaintSurface *surface)
|
2011-08-21 19:03:47 +00:00
|
|
|
{
|
2011-07-02 18:06:39 +00:00
|
|
|
PaintSurfaceData *sData = surface->data;
|
|
|
|
if (sData && sData->type_data) {
|
|
|
|
unsigned int data_size;
|
|
|
|
|
|
|
|
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT)
|
|
|
|
data_size = sizeof(PaintPoint);
|
|
|
|
else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE)
|
|
|
|
data_size = sizeof(PaintWavePoint);
|
|
|
|
else
|
|
|
|
data_size = sizeof(float);
|
|
|
|
|
|
|
|
memset(sData->type_data, 0, data_size * sData->total_points);
|
2011-08-03 18:31:48 +00:00
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* set initial color */
|
|
|
|
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT)
|
Fix #36058: Displace Modifier errors using a baked Image and displace baking inconsistency between 2.67/2.68RC and previous versions
This was in fact really nasty bug, caused by multitex_nodes
function using global variable R (which is a copy of current
renderer). this variable is not initialized to anything
meaningful for until first rendering (preview or final)
happened.
Since multitex_nodes might be used outside of render pipeline,
made it so whether CM is on or off as an argument to functions
multitex_ext_safe and multitex_ext. Now multitex_nodes() is
only shall be used for stuff happening from render pipeline!
Also needed to make some changes to other places, so all the
usages of texture sampling knows for the fact whether CM is
on or off.
And one more change is related on behavior of dispalcement,
wave, warp, weightvg modifiers and smoke. They'll be always
using CM off since texture is used for influence, not for
color.
It's rather bigger patch, but it's mostly straightforward
changes, which we really need to be done.
Reviewed by Brecht, thanks!
2013-07-15 14:47:58 +00:00
|
|
|
dynamicPaint_setInitialColor(scene, surface);
|
2011-09-05 16:04:15 +00:00
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
if (sData->bData)
|
|
|
|
sData->bData->clear = 1;
|
2011-07-02 18:06:39 +00:00
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
|
2011-07-02 18:06:39 +00:00
|
|
|
/* completely (re)initializes surface (only for point cache types)*/
|
Fix #36058: Displace Modifier errors using a baked Image and displace baking inconsistency between 2.67/2.68RC and previous versions
This was in fact really nasty bug, caused by multitex_nodes
function using global variable R (which is a copy of current
renderer). this variable is not initialized to anything
meaningful for until first rendering (preview or final)
happened.
Since multitex_nodes might be used outside of render pipeline,
made it so whether CM is on or off as an argument to functions
multitex_ext_safe and multitex_ext. Now multitex_nodes() is
only shall be used for stuff happening from render pipeline!
Also needed to make some changes to other places, so all the
usages of texture sampling knows for the fact whether CM is
on or off.
And one more change is related on behavior of dispalcement,
wave, warp, weightvg modifiers and smoke. They'll be always
using CM off since texture is used for influence, not for
color.
It's rather bigger patch, but it's mostly straightforward
changes, which we really need to be done.
Reviewed by Brecht, thanks!
2013-07-15 14:47:58 +00:00
|
|
|
int dynamicPaint_resetSurface(Scene *scene, DynamicPaintSurface *surface)
|
2011-06-16 10:41:00 +00:00
|
|
|
{
|
|
|
|
int numOfPoints = dynamicPaint_surfaceNumOfPoints(surface);
|
2012-01-24 17:28:50 +00:00
|
|
|
/* free existing data */
|
2011-06-16 10:41:00 +00:00
|
|
|
if (surface->data) dynamicPaint_freeSurfaceData(surface);
|
2012-01-24 17:28:50 +00:00
|
|
|
|
2012-03-18 07:38:51 +00:00
|
|
|
/* don't reallocate for image sequence types. they get handled only on bake */
|
2012-01-24 17:28:50 +00:00
|
|
|
if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) return 1;
|
2011-06-16 10:41:00 +00:00
|
|
|
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);
|
2011-08-03 18:31:48 +00:00
|
|
|
dynamicPaint_initAdjacencyData(surface, 0);
|
2011-06-16 10:41:00 +00:00
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* set initial color */
|
|
|
|
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT)
|
Fix #36058: Displace Modifier errors using a baked Image and displace baking inconsistency between 2.67/2.68RC and previous versions
This was in fact really nasty bug, caused by multitex_nodes
function using global variable R (which is a copy of current
renderer). this variable is not initialized to anything
meaningful for until first rendering (preview or final)
happened.
Since multitex_nodes might be used outside of render pipeline,
made it so whether CM is on or off as an argument to functions
multitex_ext_safe and multitex_ext. Now multitex_nodes() is
only shall be used for stuff happening from render pipeline!
Also needed to make some changes to other places, so all the
usages of texture sampling knows for the fact whether CM is
on or off.
And one more change is related on behavior of dispalcement,
wave, warp, weightvg modifiers and smoke. They'll be always
using CM off since texture is used for influence, not for
color.
It's rather bigger patch, but it's mostly straightforward
changes, which we really need to be done.
Reviewed by Brecht, thanks!
2013-07-15 14:47:58 +00:00
|
|
|
dynamicPaint_setInitialColor(scene, surface);
|
2011-09-05 16:04:15 +00:00
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* make sure allocated surface size matches current requirements */
|
Fix #36058: Displace Modifier errors using a baked Image and displace baking inconsistency between 2.67/2.68RC and previous versions
This was in fact really nasty bug, caused by multitex_nodes
function using global variable R (which is a copy of current
renderer). this variable is not initialized to anything
meaningful for until first rendering (preview or final)
happened.
Since multitex_nodes might be used outside of render pipeline,
made it so whether CM is on or off as an argument to functions
multitex_ext_safe and multitex_ext. Now multitex_nodes() is
only shall be used for stuff happening from render pipeline!
Also needed to make some changes to other places, so all the
usages of texture sampling knows for the fact whether CM is
on or off.
And one more change is related on behavior of dispalcement,
wave, warp, weightvg modifiers and smoke. They'll be always
using CM off since texture is used for influence, not for
color.
It's rather bigger patch, but it's mostly straightforward
changes, which we really need to be done.
Reviewed by Brecht, thanks!
2013-07-15 14:47:58 +00:00
|
|
|
static int dynamicPaint_checkSurfaceData(Scene *scene, DynamicPaintSurface *surface)
|
2011-06-16 10:41:00 +00:00
|
|
|
{
|
|
|
|
if (!surface->data || ((dynamicPaint_surfaceNumOfPoints(surface) != surface->data->total_points))) {
|
Fix #36058: Displace Modifier errors using a baked Image and displace baking inconsistency between 2.67/2.68RC and previous versions
This was in fact really nasty bug, caused by multitex_nodes
function using global variable R (which is a copy of current
renderer). this variable is not initialized to anything
meaningful for until first rendering (preview or final)
happened.
Since multitex_nodes might be used outside of render pipeline,
made it so whether CM is on or off as an argument to functions
multitex_ext_safe and multitex_ext. Now multitex_nodes() is
only shall be used for stuff happening from render pipeline!
Also needed to make some changes to other places, so all the
usages of texture sampling knows for the fact whether CM is
on or off.
And one more change is related on behavior of dispalcement,
wave, warp, weightvg modifiers and smoke. They'll be always
using CM off since texture is used for influence, not for
color.
It's rather bigger patch, but it's mostly straightforward
changes, which we really need to be done.
Reviewed by Brecht, thanks!
2013-07-15 14:47:58 +00:00
|
|
|
return dynamicPaint_resetSurface(scene, surface);
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
2011-11-20 10:52:25 +00:00
|
|
|
return 1;
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************** Modifier processing ******************************/
|
|
|
|
|
|
|
|
|
2011-08-05 09:31:35 +00:00
|
|
|
/* apply displacing vertex surface to the derived mesh */
|
2012-01-16 17:18:07 +00:00
|
|
|
static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, DerivedMesh *result)
|
2011-06-16 10:41:00 +00:00
|
|
|
{
|
2011-08-05 09:31:35 +00:00
|
|
|
PaintSurfaceData *sData = surface->data;
|
2011-06-16 10:41:00 +00:00
|
|
|
|
2011-08-05 09:31:35 +00:00
|
|
|
if (!sData || surface->format != MOD_DPAINT_SURFACE_F_VERTEX) return;
|
2011-06-16 10:41:00 +00:00
|
|
|
|
2011-08-05 09:31:35 +00:00
|
|
|
/* displace paint */
|
|
|
|
if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
|
|
|
|
MVert *mvert = result->getVertArray(result);
|
|
|
|
int i;
|
2012-05-12 16:11:34 +00:00
|
|
|
float *value = (float *)sData->type_data;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < sData->total_points; i++) {
|
|
|
|
float normal[3], val = value[i] * surface->disp_factor;
|
2011-08-05 09:31:35 +00:00
|
|
|
normal_short_to_float_v3(normal, mvert[i].no);
|
|
|
|
normalize_v3(normal);
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
mvert[i].co[0] -= normal[0] * val;
|
|
|
|
mvert[i].co[1] -= normal[1] * val;
|
|
|
|
mvert[i].co[2] -= normal[2] * val;
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* Apply canvas data to the object derived mesh
|
|
|
|
*/
|
2012-09-15 01:52:28 +00:00
|
|
|
static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd,
|
2012-05-17 23:21:11 +00:00
|
|
|
Object *ob,
|
|
|
|
DerivedMesh *dm)
|
|
|
|
{
|
2012-01-29 21:59:47 +00:00
|
|
|
DerivedMesh *result = CDDM_copy(dm);
|
2011-06-16 10:41:00 +00:00
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
if (pmd->canvas && !(pmd->canvas->flags & MOD_DPAINT_BAKING)) {
|
2011-06-16 10:41:00 +00:00
|
|
|
|
2012-04-23 16:29:13 +00:00
|
|
|
DynamicPaintSurface *surface;
|
2013-07-06 01:42:45 +00:00
|
|
|
bool update_normals = false;
|
2011-06-16 10:41:00 +00:00
|
|
|
|
|
|
|
/* loop through surfaces */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
|
2011-08-03 18:31:48 +00:00
|
|
|
PaintSurfaceData *sData = surface->data;
|
2011-06-16 10:41:00 +00:00
|
|
|
|
2012-04-23 16:29:13 +00:00
|
|
|
if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ && sData) {
|
2011-06-16 10:41:00 +00:00
|
|
|
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) {
|
|
|
|
|
2011-06-18 18:41:20 +00:00
|
|
|
int i;
|
2012-05-12 16:11:34 +00:00
|
|
|
PaintPoint *pPoint = (PaintPoint *)sData->type_data;
|
2011-11-30 20:41:13 +00:00
|
|
|
MLoopCol *col = NULL;
|
|
|
|
MLoop *mloop = CDDM_get_loops(result);
|
|
|
|
int totloop = result->numLoopData;
|
2011-06-16 10:41:00 +00:00
|
|
|
|
|
|
|
/* paint is stored on dry and wet layers, so mix final color first */
|
2012-05-12 16:11:34 +00:00
|
|
|
float *fcolor = MEM_callocN(sizeof(float) * sData->total_points * 4, "Temp paint color");
|
2011-06-18 18:41:20 +00:00
|
|
|
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < sData->total_points; i++) {
|
2011-10-31 13:01:06 +00:00
|
|
|
/* blend dry and wet layer */
|
2012-05-12 16:11:34 +00:00
|
|
|
blendColors(pPoint[i].color, pPoint[i].alpha, pPoint[i].e_color, pPoint[i].e_alpha, &fcolor[i * 4]);
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* viewport preview */
|
2012-01-23 16:32:11 +00:00
|
|
|
if (surface->flags & MOD_DPAINT_PREVIEW) {
|
2011-11-30 20:41:13 +00:00
|
|
|
MPoly *mp = CDDM_get_polys(result);
|
|
|
|
int totpoly = result->numPolyData;
|
|
|
|
|
Fix [#30234] Various problems with CD layers and tesselation, related to modifiers stack.
Should also fix [#30266], [#29451], and partly [#30316].
Here are the changes made by this commit:
* It adds a "dirty" flag to DerivedMesh struct (for now, only DM_DIRTY_TESS_CDLAYERS, but more might be added as needed).
* It adds a new func, DM_update_tessface_data, which assumes tessfaces themselves are valid, but updates tessellated customdata from their poly/loop counter parts.
* At end of modstack, when valid tessellated faces are present in finaldm , but the cdlayers dirty flag is set, call that function (instead of recomputing the whole tessellation).
* Edits to the codes concerned (UVProject, DynamicPaint, and Subsurf modifiers).
* Also add to subsurf dm generation code the creation of a CD_POLYINDEX layer (mandatory for DM_update_tessface_data to work well, and imho all tessellated dm should have one).
Note: some pieces of old code are just #if 0’ed, will clean them later.
2012-03-18 22:06:57 +00:00
|
|
|
#if 0
|
2012-03-22 08:41:50 +00:00
|
|
|
/* XXX We have to create a CD_PREVIEW_MCOL, else it might sigsev
|
2012-01-23 17:17:08 +00:00
|
|
|
* (after a SubSurf mod, eg)... */
|
2012-03-24 06:18:31 +00:00
|
|
|
if (!result->getTessFaceDataArray(result, CD_PREVIEW_MCOL)) {
|
2012-01-23 17:17:08 +00:00
|
|
|
int numFaces = result->getNumTessFaces(result);
|
2012-03-22 08:41:50 +00:00
|
|
|
CustomData_add_layer(&result->faceData, CD_PREVIEW_MCOL, CD_CALLOC, NULL, numFaces);
|
2012-01-23 17:17:08 +00:00
|
|
|
}
|
Fix [#30234] Various problems with CD layers and tesselation, related to modifiers stack.
Should also fix [#30266], [#29451], and partly [#30316].
Here are the changes made by this commit:
* It adds a "dirty" flag to DerivedMesh struct (for now, only DM_DIRTY_TESS_CDLAYERS, but more might be added as needed).
* It adds a new func, DM_update_tessface_data, which assumes tessfaces themselves are valid, but updates tessellated customdata from their poly/loop counter parts.
* At end of modstack, when valid tessellated faces are present in finaldm , but the cdlayers dirty flag is set, call that function (instead of recomputing the whole tessellation).
* Edits to the codes concerned (UVProject, DynamicPaint, and Subsurf modifiers).
* Also add to subsurf dm generation code the creation of a CD_POLYINDEX layer (mandatory for DM_update_tessface_data to work well, and imho all tessellated dm should have one).
Note: some pieces of old code are just #if 0’ed, will clean them later.
2012-03-18 22:06:57 +00:00
|
|
|
#endif
|
2012-01-23 17:17:08 +00:00
|
|
|
|
2011-11-30 20:41:13 +00:00
|
|
|
/* Save preview results to weight layer to be
|
2012-05-12 16:11:34 +00:00
|
|
|
* able to share same drawing methods */
|
2012-03-22 08:41:50 +00:00
|
|
|
col = CustomData_get_layer(&result->loopData, CD_PREVIEW_MLOOPCOL);
|
|
|
|
if (!col)
|
|
|
|
col = CustomData_add_layer(&result->loopData, CD_PREVIEW_MLOOPCOL, CD_CALLOC,
|
|
|
|
NULL, totloop);
|
2011-06-16 10:41:00 +00:00
|
|
|
|
|
|
|
if (col) {
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < totpoly; i++) {
|
|
|
|
int j = 0;
|
2012-04-02 22:26:00 +00:00
|
|
|
Material *material = give_current_material(ob, mp[i].mat_nr + 1);
|
2011-06-16 10:41:00 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
for (; j < mp[i].totloop; j++) {
|
2011-11-30 20:41:13 +00:00
|
|
|
int l_index = mp[i].loopstart + j;
|
|
|
|
int v_index = mloop[l_index].v;
|
2011-06-16 10:41:00 +00:00
|
|
|
|
2011-08-28 16:36:47 +00:00
|
|
|
if (surface->preview_id == MOD_DPAINT_SURFACE_PREV_PAINT) {
|
2011-10-28 14:46:09 +00:00
|
|
|
float c[3];
|
2011-11-30 20:41:13 +00:00
|
|
|
v_index *= 4;
|
2011-08-28 16:36:47 +00:00
|
|
|
|
|
|
|
/* Apply material color as base vertex color for preview */
|
2011-11-30 20:41:13 +00:00
|
|
|
col[l_index].a = 255;
|
2011-08-28 16:36:47 +00:00
|
|
|
if (material) {
|
2011-10-28 14:46:09 +00:00
|
|
|
c[0] = material->r;
|
|
|
|
c[1] = material->g;
|
|
|
|
c[2] = material->b;
|
2011-08-28 16:36:47 +00:00
|
|
|
}
|
2012-07-03 19:09:07 +00:00
|
|
|
else { /* default gray */
|
2011-10-28 14:46:09 +00:00
|
|
|
c[0] = 0.65f;
|
|
|
|
c[1] = 0.65f;
|
|
|
|
c[2] = 0.65f;
|
2011-08-28 16:36:47 +00:00
|
|
|
}
|
|
|
|
/* mix surface color */
|
2012-05-12 16:11:34 +00:00
|
|
|
interp_v3_v3v3(c, c, &fcolor[v_index], fcolor[v_index + 3]);
|
2011-10-28 14:46:09 +00:00
|
|
|
|
2012-03-17 20:39:28 +00:00
|
|
|
rgb_float_to_uchar((unsigned char *)&col[l_index].r, c);
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-01-15 09:16:39 +00:00
|
|
|
col[l_index].r =
|
2012-05-12 16:11:34 +00:00
|
|
|
col[l_index].g =
|
|
|
|
col[l_index].b = FTOCHAR(pPoint[v_index].wetness);
|
2012-03-17 20:39:28 +00:00
|
|
|
col[l_index].a = 255;
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* save layer data to output layer */
|
|
|
|
|
|
|
|
/* paint layer */
|
2011-11-30 20:41:13 +00:00
|
|
|
col = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name);
|
2011-11-20 10:52:25 +00:00
|
|
|
/* if output layer is lost from a constructive modifier, re-add it */
|
|
|
|
if (!col && dynamicPaint_outputLayerExists(surface, ob, 0))
|
2011-11-30 20:41:13 +00:00
|
|
|
col = CustomData_add_layer_named(&result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name);
|
2011-11-20 10:52:25 +00:00
|
|
|
/* apply color */
|
2011-06-16 10:41:00 +00:00
|
|
|
if (col) {
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < totloop; i++) {
|
|
|
|
int index = mloop[i].v * 4;
|
2012-03-17 20:39:28 +00:00
|
|
|
rgb_float_to_uchar((unsigned char *)&col[i].r, &fcolor[index]);
|
2012-05-12 16:11:34 +00:00
|
|
|
col[i].a = FTOCHAR(fcolor[index + 3]); /* IS THIS NEEDED? */
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
}
|
2011-07-24 17:03:33 +00:00
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
MEM_freeN(fcolor);
|
|
|
|
|
|
|
|
/* wet layer */
|
2011-11-30 20:41:13 +00:00
|
|
|
col = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name2);
|
2011-11-20 10:52:25 +00:00
|
|
|
/* if output layer is lost from a constructive modifier, re-add it */
|
|
|
|
if (!col && dynamicPaint_outputLayerExists(surface, ob, 1))
|
2011-11-30 20:41:13 +00:00
|
|
|
col = CustomData_add_layer_named(&result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2);
|
2011-11-20 10:52:25 +00:00
|
|
|
/* apply color */
|
2011-06-16 10:41:00 +00:00
|
|
|
if (col) {
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < totloop; i++) {
|
2011-11-30 20:41:13 +00:00
|
|
|
int index = mloop[i].v;
|
2012-01-15 09:16:39 +00:00
|
|
|
col[i].r =
|
2012-05-12 16:11:34 +00:00
|
|
|
col[i].g =
|
|
|
|
col[i].b = FTOCHAR(pPoint[index].wetness);
|
2012-03-17 20:39:28 +00:00
|
|
|
col[i].a = 255;
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
}
|
Fix [#30234] Various problems with CD layers and tesselation, related to modifiers stack.
Should also fix [#30266], [#29451], and partly [#30316].
Here are the changes made by this commit:
* It adds a "dirty" flag to DerivedMesh struct (for now, only DM_DIRTY_TESS_CDLAYERS, but more might be added as needed).
* It adds a new func, DM_update_tessface_data, which assumes tessfaces themselves are valid, but updates tessellated customdata from their poly/loop counter parts.
* At end of modstack, when valid tessellated faces are present in finaldm , but the cdlayers dirty flag is set, call that function (instead of recomputing the whole tessellation).
* Edits to the codes concerned (UVProject, DynamicPaint, and Subsurf modifiers).
* Also add to subsurf dm generation code the creation of a CD_POLYINDEX layer (mandatory for DM_update_tessface_data to work well, and imho all tessellated dm should have one).
Note: some pieces of old code are just #if 0’ed, will clean them later.
2012-03-18 22:06:57 +00:00
|
|
|
|
|
|
|
/* Mark tessellated CD layers as dirty. */
|
|
|
|
result->dirty |= DM_DIRTY_TESS_CDLAYERS;
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
/* vertex group paint */
|
|
|
|
else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
|
2011-06-18 18:41:20 +00:00
|
|
|
int defgrp_index = defgroup_name_index(ob, surface->output_name);
|
|
|
|
MDeformVert *dvert = result->getVertDataArray(result, CD_MDEFORMVERT);
|
2012-05-12 16:11:34 +00:00
|
|
|
float *weight = (float *)sData->type_data;
|
2011-11-30 20:41:13 +00:00
|
|
|
|
2011-06-18 18:41:20 +00:00
|
|
|
/* viewport preview */
|
2012-01-23 16:32:11 +00:00
|
|
|
if (surface->flags & MOD_DPAINT_PREVIEW) {
|
2011-11-30 20:41:13 +00:00
|
|
|
/* Save preview results to weight layer to be
|
Fix [#30234] Various problems with CD layers and tesselation, related to modifiers stack.
Should also fix [#30266], [#29451], and partly [#30316].
Here are the changes made by this commit:
* It adds a "dirty" flag to DerivedMesh struct (for now, only DM_DIRTY_TESS_CDLAYERS, but more might be added as needed).
* It adds a new func, DM_update_tessface_data, which assumes tessfaces themselves are valid, but updates tessellated customdata from their poly/loop counter parts.
* At end of modstack, when valid tessellated faces are present in finaldm , but the cdlayers dirty flag is set, call that function (instead of recomputing the whole tessellation).
* Edits to the codes concerned (UVProject, DynamicPaint, and Subsurf modifiers).
* Also add to subsurf dm generation code the creation of a CD_POLYINDEX layer (mandatory for DM_update_tessface_data to work well, and imho all tessellated dm should have one).
Note: some pieces of old code are just #if 0’ed, will clean them later.
2012-03-18 22:06:57 +00:00
|
|
|
* able to share same drawing methods.
|
|
|
|
* Note this func also sets DM_DIRTY_TESS_CDLAYERS flag! */
|
Add weight preview to WeightVG modifiers, and first, simple/basic refactor of how modifiers can generate preview.
User side:
* Preview for DynamicPaint should keep the same behavior (for now). Weight preview should be somawhat quicker, though.
* Preview for WeightVG modifiers is only active in WeightPaint mode, and if the affected vgroup is the active one.
* Last active preview modifier in stack wins!
Note: that modifier preview topic is yet to be further refined, quite raw/incomplete for now.
Dev side:
* In draw code, renamed DRAW_DYNAMIC_PAINT_PREVIEW flag to DRAW_MODIFIERS_PREVIEW
* Removed use of MOD_DPAINT_PREVIEW_READY in DynamicPaint code (seems unecessary, and if it was, should be of more general scope).
* Added eModifierTypeFlag_UsesPreview to ModifierTypeFlag, for modifiers that can generate some preview data.
* Added three new modifier funcs, to handle preview modifiers in draw code / mod stack.
* For weights preview: added the generic DM_update_weight_mcol func, which can update WEIGHT_MCOL layer with either a given array of weights (currently used by DynamicPaint only), or from current active vgroup(s).
So now, draw code is fully generic (i.e. no more modifier-type checking in it). Mod stack code is generic to some extent, but will need more work.
2012-01-22 17:54:23 +00:00
|
|
|
DM_update_weight_mcol(ob, result, 0, weight, 0, NULL);
|
2011-06-18 18:41:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* apply weights into a vertex group, if doesnt exists add a new layer */
|
2012-10-22 17:19:05 +00:00
|
|
|
if (defgrp_index != -1 && !dvert && (surface->output_name[0] != '\0'))
|
2011-06-18 18:41:20 +00:00
|
|
|
dvert = CustomData_add_layer_named(&result->vertData, CD_MDEFORMVERT, CD_CALLOC,
|
2012-05-12 16:11:34 +00:00
|
|
|
NULL, sData->total_points, surface->output_name);
|
2012-10-22 17:19:05 +00:00
|
|
|
if (defgrp_index != -1 && dvert) {
|
2011-06-18 18:41:20 +00:00
|
|
|
int i;
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < sData->total_points; i++) {
|
|
|
|
MDeformVert *dv = &dvert[i];
|
2011-10-28 14:46:09 +00:00
|
|
|
MDeformWeight *def_weight = defvert_find_index(dv, defgrp_index);
|
2011-06-18 18:41:20 +00:00
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
/* skip if weight value is 0 and no existing weight is found */
|
2011-11-30 10:04:14 +00:00
|
|
|
if ((def_weight != NULL) || (weight[i] != 0.0f)) {
|
|
|
|
|
|
|
|
/* if not found, add a weight for it */
|
|
|
|
if (def_weight == NULL) {
|
2012-05-12 16:11:34 +00:00
|
|
|
def_weight = defvert_verify_index(dv, defgrp_index);
|
2011-06-18 18:41:20 +00:00
|
|
|
}
|
|
|
|
|
2011-11-30 10:04:14 +00:00
|
|
|
/* set weight value */
|
|
|
|
def_weight->weight = weight[i];
|
|
|
|
}
|
2011-06-18 18:41:20 +00:00
|
|
|
}
|
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
2011-07-02 18:06:39 +00:00
|
|
|
/* wave simulation */
|
|
|
|
else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
|
|
|
|
MVert *mvert = result->getVertArray(result);
|
|
|
|
int i;
|
2012-05-12 16:11:34 +00:00
|
|
|
PaintWavePoint *wPoint = (PaintWavePoint *)sData->type_data;
|
2011-07-02 18:06:39 +00:00
|
|
|
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < sData->total_points; i++) {
|
2011-07-22 18:37:30 +00:00
|
|
|
float normal[3];
|
2011-07-02 18:06:39 +00:00
|
|
|
normal_short_to_float_v3(normal, mvert[i].no);
|
2011-11-30 10:04:14 +00:00
|
|
|
madd_v3_v3fl(mvert[i].co, normal, wPoint[i].height);
|
2011-07-02 18:06:39 +00:00
|
|
|
}
|
2013-07-06 01:42:45 +00:00
|
|
|
update_normals = true;
|
2011-07-02 18:06:39 +00:00
|
|
|
}
|
2011-08-05 09:31:35 +00:00
|
|
|
|
|
|
|
/* displace */
|
2012-01-16 17:18:07 +00:00
|
|
|
if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
|
|
|
|
dynamicPaint_applySurfaceDisplace(surface, result);
|
2013-07-06 01:42:45 +00:00
|
|
|
update_normals = true;
|
2012-01-16 17:18:07 +00:00
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-01-16 17:18:07 +00:00
|
|
|
|
2013-07-06 01:42:45 +00:00
|
|
|
if (update_normals) {
|
|
|
|
result->dirty |= DM_DIRTY_NORMALS;
|
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
2011-07-08 11:03:37 +00:00
|
|
|
/* make a copy of dm to use as brush data */
|
|
|
|
if (pmd->brush) {
|
|
|
|
if (pmd->brush->dm) pmd->brush->dm->release(pmd->brush->dm);
|
2012-01-29 21:59:47 +00:00
|
|
|
pmd->brush->dm = CDDM_copy(result);
|
2011-07-08 11:03:37 +00:00
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
return result;
|
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-08-05 09:31:35 +00:00
|
|
|
/* update cache frame range */
|
|
|
|
void dynamicPaint_cacheUpdateFrames(DynamicPaintSurface *surface)
|
|
|
|
{
|
|
|
|
if (surface->pointcache) {
|
|
|
|
surface->pointcache->startframe = surface->start_frame;
|
|
|
|
surface->pointcache->endframe = surface->end_frame;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-15 01:52:28 +00:00
|
|
|
static void canvas_copyDerivedMesh(DynamicPaintCanvasSettings *canvas, DerivedMesh *dm)
|
2011-08-05 09:31:35 +00:00
|
|
|
{
|
2012-09-15 01:52:28 +00:00
|
|
|
if (canvas->dm) {
|
|
|
|
canvas->dm->release(canvas->dm);
|
|
|
|
}
|
|
|
|
|
2012-01-29 21:59:47 +00:00
|
|
|
canvas->dm = CDDM_copy(dm);
|
2011-08-05 09:31:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* Updates derived mesh copy and processes dynamic paint step / caches.
|
|
|
|
*/
|
2011-08-05 09:31:35 +00:00
|
|
|
static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm)
|
|
|
|
{
|
2012-03-24 06:18:31 +00:00
|
|
|
if (pmd->canvas) {
|
2011-08-05 09:31:35 +00:00
|
|
|
DynamicPaintCanvasSettings *canvas = pmd->canvas;
|
|
|
|
DynamicPaintSurface *surface = canvas->surfaces.first;
|
|
|
|
|
|
|
|
/* update derived mesh copy */
|
|
|
|
canvas_copyDerivedMesh(canvas, dm);
|
|
|
|
|
|
|
|
/* in case image sequence baking, stop here */
|
|
|
|
if (canvas->flags & MOD_DPAINT_BAKING) return;
|
|
|
|
|
|
|
|
/* loop through surfaces */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (; surface; surface = surface->next) {
|
2011-08-05 09:31:35 +00:00
|
|
|
int current_frame = (int)scene->r.cfra;
|
2013-07-12 16:33:37 +00:00
|
|
|
bool no_surface_data;
|
2011-08-05 09:31:35 +00:00
|
|
|
|
2011-08-21 19:03:47 +00:00
|
|
|
/* free bake data if not required anymore */
|
|
|
|
surface_freeUnusedData(surface);
|
|
|
|
|
2011-08-05 09:31:35 +00:00
|
|
|
/* 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 */
|
2013-07-12 16:33:37 +00:00
|
|
|
no_surface_data = surface->data == NULL;
|
Fix #36058: Displace Modifier errors using a baked Image and displace baking inconsistency between 2.67/2.68RC and previous versions
This was in fact really nasty bug, caused by multitex_nodes
function using global variable R (which is a copy of current
renderer). this variable is not initialized to anything
meaningful for until first rendering (preview or final)
happened.
Since multitex_nodes might be used outside of render pipeline,
made it so whether CM is on or off as an argument to functions
multitex_ext_safe and multitex_ext. Now multitex_nodes() is
only shall be used for stuff happening from render pipeline!
Also needed to make some changes to other places, so all the
usages of texture sampling knows for the fact whether CM is
on or off.
And one more change is related on behavior of dispalcement,
wave, warp, weightvg modifiers and smoke. They'll be always
using CM off since texture is used for influence, not for
color.
It's rather bigger patch, but it's mostly straightforward
changes, which we really need to be done.
Reviewed by Brecht, thanks!
2013-07-15 14:47:58 +00:00
|
|
|
if (!dynamicPaint_checkSurfaceData(scene, surface)) continue;
|
2011-08-05 09:31:35 +00:00
|
|
|
|
|
|
|
/* limit frame range */
|
|
|
|
CLAMP(current_frame, surface->start_frame, surface->end_frame);
|
|
|
|
|
2013-07-12 16:33:37 +00:00
|
|
|
if (no_surface_data || current_frame != surface->current_frame || (int)scene->r.cfra == surface->start_frame) {
|
2011-08-05 09:31:35 +00:00
|
|
|
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;
|
2011-11-10 13:00:27 +00:00
|
|
|
BKE_ptcache_id_time(&pid, scene, (float)scene->r.cfra, NULL, NULL, NULL);
|
2011-08-05 09:31:35 +00:00
|
|
|
|
|
|
|
/* reset non-baked cache at first frame */
|
2012-04-21 15:11:03 +00:00
|
|
|
if ((int)scene->r.cfra == surface->start_frame && !(cache->flag & PTCACHE_BAKED)) {
|
2011-08-05 09:31:35 +00:00
|
|
|
cache->flag |= PTCACHE_REDO_NEEDED;
|
|
|
|
BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
|
|
|
|
cache->flag &= ~PTCACHE_REDO_NEEDED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* try to read from cache */
|
2012-03-24 06:18:31 +00:00
|
|
|
if (BKE_ptcache_read(&pid, (float)scene->r.cfra)) {
|
2011-08-05 09:31:35 +00:00
|
|
|
BKE_ptcache_validate(cache, (int)scene->r.cfra);
|
|
|
|
}
|
|
|
|
/* if read failed and we're on surface range do recalculate */
|
2012-04-21 15:11:03 +00:00
|
|
|
else if ((int)scene->r.cfra == current_frame && !(cache->flag & PTCACHE_BAKED)) {
|
2011-08-05 09:31:35 +00:00
|
|
|
/* calculate surface frame */
|
|
|
|
canvas->flags |= MOD_DPAINT_BAKING;
|
|
|
|
dynamicPaint_calculateFrame(surface, scene, ob, current_frame);
|
|
|
|
canvas->flags &= ~MOD_DPAINT_BAKING;
|
|
|
|
|
|
|
|
/* restore canvas derivedmesh if required */
|
|
|
|
if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE &&
|
2012-04-28 06:31:57 +00:00
|
|
|
surface->flags & MOD_DPAINT_DISP_INCREMENTAL && surface->next)
|
|
|
|
{
|
2011-08-05 09:31:35 +00:00
|
|
|
canvas_copyDerivedMesh(canvas, dm);
|
2012-04-28 06:31:57 +00:00
|
|
|
}
|
2011-08-05 09:31:35 +00:00
|
|
|
|
|
|
|
BKE_ptcache_validate(cache, surface->current_frame);
|
|
|
|
BKE_ptcache_write(&pid, surface->current_frame);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/* Modifier call. Processes dynamic paint modifier step. */
|
2012-05-17 23:21:11 +00:00
|
|
|
DerivedMesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm)
|
|
|
|
{
|
2012-01-24 18:29:01 +00:00
|
|
|
/* For now generate tessfaces in every case
|
2012-05-12 16:11:34 +00:00
|
|
|
* XXX - move/remove when most of dpaint functions are converted to use bmesh types */
|
2012-01-24 18:29:01 +00:00
|
|
|
DM_ensure_tessface(dm);
|
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
/* Update canvas data for a new frame */
|
2011-07-08 11:03:37 +00:00
|
|
|
dynamicPaint_frameUpdate(pmd, scene, ob, dm);
|
2011-06-16 10:41:00 +00:00
|
|
|
|
|
|
|
/* Return output mesh */
|
2011-11-10 13:00:27 +00:00
|
|
|
return dynamicPaint_Modifier_apply(pmd, ob, dm);
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/***************************** Image Sequence / UV Image Surface Calls ******************************/
|
2011-06-16 10:41:00 +00:00
|
|
|
|
2011-05-24 07:08:58 +00:00
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* Tries to find the neighboring pixel in given (uv space) direction.
|
|
|
|
* Result is used by effect system to move paint on the surface.
|
|
|
|
*
|
|
|
|
* px, py : origin pixel x and y
|
|
|
|
* n_index : lookup direction index (use neighX, neighY to get final index)
|
|
|
|
*/
|
2012-01-11 12:56:31 +00:00
|
|
|
static int dynamicPaint_findNeighbourPixel(PaintUVPoint *tempPoints, DerivedMesh *dm,
|
|
|
|
const char *uvname, int w, int h, int px, int py, int n_index)
|
2011-05-24 07:08:58 +00:00
|
|
|
{
|
2012-03-01 12:20:18 +00:00
|
|
|
/* Note: Current method only uses polygon edges to detect neighboring pixels.
|
2012-05-12 16:11:34 +00:00
|
|
|
* -> It doesn't always lead to the optimum pixel but is accurate enough
|
2012-09-26 20:05:38 +00:00
|
|
|
* and faster/simpler than including possible face tip point links)
|
2012-05-12 16:11:34 +00:00
|
|
|
*/
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-04-29 15:47:02 +00:00
|
|
|
int x, y;
|
2011-06-27 07:30:58 +00:00
|
|
|
PaintUVPoint *tPoint = NULL;
|
|
|
|
PaintUVPoint *cPoint = NULL;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
/* shift position by given n_index */
|
2011-05-24 07:08:58 +00:00
|
|
|
x = px + neighX[n_index];
|
|
|
|
y = py + neighY[n_index];
|
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
if (x < 0 || x >= w) return OUT_OF_TEXTURE;
|
|
|
|
if (y < 0 || y >= h) return OUT_OF_TEXTURE;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
tPoint = &tempPoints[x + w * y]; /* UV neighbor */
|
|
|
|
cPoint = &tempPoints[px + w * py]; /* Origin point */
|
2011-05-24 07:08:58 +00:00
|
|
|
|
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* Check if shifted point is on same face -> it's a correct neighbor
|
|
|
|
* (and if it isn't marked as an "edge pixel")
|
|
|
|
*/
|
2011-06-27 07:30:58 +00:00
|
|
|
if ((tPoint->face_index == cPoint->face_index) && (tPoint->neighbour_pixel == -1))
|
2012-05-12 16:11:34 +00:00
|
|
|
return (x + w * y);
|
2011-05-24 07:08:58 +00:00
|
|
|
|
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* Even if shifted point is on another face
|
|
|
|
* -> use this point.
|
|
|
|
*
|
|
|
|
* !! Replace with "is uv faces linked" check !!
|
|
|
|
* This should work fine as long as uv island
|
|
|
|
* margin is > 1 pixel.
|
|
|
|
*/
|
2011-06-27 07:30:58 +00:00
|
|
|
if ((tPoint->face_index != -1) && (tPoint->neighbour_pixel == -1)) {
|
2012-05-12 16:11:34 +00:00
|
|
|
return (x + w * y);
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* If we get here, the actual neighboring pixel
|
|
|
|
* is located on a non-linked uv face, and we have to find
|
|
|
|
* it's "real" position.
|
|
|
|
*
|
|
|
|
* Simple neighboring face finding algorithm:
|
|
|
|
* - find closest uv edge to shifted pixel and get
|
|
|
|
* the another face that shares that edge
|
|
|
|
* - find corresponding position of that new face edge
|
|
|
|
* in uv space
|
|
|
|
*
|
|
|
|
* TODO: Implement something more accurate / optimized?
|
|
|
|
*/
|
2011-05-24 07:08:58 +00:00
|
|
|
{
|
2011-11-11 11:20:46 +00:00
|
|
|
int numOfFaces = dm->getNumTessFaces(dm);
|
|
|
|
MFace *mface = dm->getTessFaceArray(dm);
|
2011-12-08 00:28:42 +00:00
|
|
|
MTFace *tface = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, uvname);
|
2011-05-24 07:08:58 +00:00
|
|
|
|
|
|
|
/* Get closest edge to that subpixel on UV map */
|
|
|
|
{
|
2012-08-14 08:44:35 +00:00
|
|
|
float pixel[2];
|
|
|
|
/* distances only used for comparison */
|
|
|
|
float dist_squared, t_dist_squared;
|
|
|
|
|
2011-11-13 13:56:40 +00:00
|
|
|
int i, uindex[3], edge1_index, edge2_index,
|
2012-05-12 16:11:34 +00:00
|
|
|
e1_index, e2_index, target_face;
|
2011-05-24 07:08:58 +00:00
|
|
|
float closest_point[2], lambda, dir_vec[2];
|
|
|
|
int target_uv1, target_uv2, final_pixel[2], final_index;
|
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
float *s_uv1, *s_uv2, *t_uv1, *t_uv2;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
pixel[0] = ((float)(px + neighX[n_index]) + 0.5f) / (float)w;
|
|
|
|
pixel[1] = ((float)(py + neighY[n_index]) + 0.5f) / (float)h;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
|
|
|
/* Get uv indexes for current face part */
|
|
|
|
if (cPoint->quad) {
|
|
|
|
uindex[0] = 0; uindex[1] = 2; uindex[2] = 3;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
uindex[0] = 0; uindex[1] = 1; uindex[2] = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* Find closest edge to that pixel
|
|
|
|
*/
|
2012-08-14 08:44:35 +00:00
|
|
|
/* Dist to first edge */
|
2011-05-24 07:08:58 +00:00
|
|
|
e1_index = cPoint->v1; e2_index = cPoint->v2; edge1_index = uindex[0]; edge2_index = uindex[1];
|
2012-08-14 08:44:35 +00:00
|
|
|
dist_squared = dist_squared_to_line_segment_v2(pixel, tface[cPoint->face_index].uv[edge1_index], tface[cPoint->face_index].uv[edge2_index]);
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-08-14 08:44:35 +00:00
|
|
|
/* Dist to second edge */
|
|
|
|
t_dist_squared = dist_squared_to_line_segment_v2(pixel, tface[cPoint->face_index].uv[uindex[1]], tface[cPoint->face_index].uv[uindex[2]]);
|
|
|
|
if (t_dist_squared < dist_squared) { e1_index = cPoint->v2; e2_index = cPoint->v3; edge1_index = uindex[1]; edge2_index = uindex[2]; dist_squared = t_dist_squared; }
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-08-14 08:44:35 +00:00
|
|
|
/* Dist to third edge */
|
|
|
|
t_dist_squared = dist_squared_to_line_segment_v2(pixel, tface[cPoint->face_index].uv[uindex[2]], tface[cPoint->face_index].uv[uindex[0]]);
|
|
|
|
if (t_dist_squared < dist_squared) { e1_index = cPoint->v3; e2_index = cPoint->v1; edge1_index = uindex[2]; edge2_index = uindex[0]; dist_squared = t_dist_squared; }
|
2011-05-24 07:08:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* Now find another face that is linked to that edge
|
|
|
|
*/
|
2011-05-24 07:08:58 +00:00
|
|
|
target_face = -1;
|
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < numOfFaces; i++) {
|
2011-05-24 07:08:58 +00:00
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* Check if both edge vertices share this face
|
|
|
|
*/
|
2011-06-27 07:30:58 +00:00
|
|
|
int v4 = (mface[i].v4) ? mface[i].v4 : -1;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
|
|
|
if ((e1_index == mface[i].v1 || e1_index == mface[i].v2 || e1_index == mface[i].v3 || e1_index == v4) &&
|
2012-05-20 19:49:27 +00:00
|
|
|
(e2_index == mface[i].v1 || e2_index == mface[i].v2 || e2_index == mface[i].v3 || e2_index == v4))
|
|
|
|
{
|
2011-06-27 07:30:58 +00:00
|
|
|
if (i == cPoint->face_index) continue;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
|
|
|
target_face = i;
|
|
|
|
|
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* Get edge UV index
|
|
|
|
*/
|
2011-05-24 07:08:58 +00:00
|
|
|
if (e1_index == mface[i].v1) target_uv1 = 0;
|
|
|
|
else if (e1_index == mface[i].v2) target_uv1 = 1;
|
|
|
|
else if (e1_index == mface[i].v3) target_uv1 = 2;
|
|
|
|
else target_uv1 = 3;
|
|
|
|
|
|
|
|
if (e2_index == mface[i].v1) target_uv2 = 0;
|
|
|
|
else if (e2_index == mface[i].v2) target_uv2 = 1;
|
|
|
|
else if (e2_index == mface[i].v3) target_uv2 = 2;
|
|
|
|
else target_uv2 = 3;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-24 17:28:50 +00:00
|
|
|
/* If none found pixel is on mesh edge */
|
|
|
|
if (target_face == -1) return ON_MESH_EDGE;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* If target face is connected in UV space as well, just use original index
|
|
|
|
*/
|
2011-06-27 07:30:58 +00:00
|
|
|
s_uv1 = (float *)tface[cPoint->face_index].uv[edge1_index];
|
|
|
|
s_uv2 = (float *)tface[cPoint->face_index].uv[edge2_index];
|
2011-05-24 07:08:58 +00:00
|
|
|
t_uv1 = (float *)tface[target_face].uv[target_uv1];
|
|
|
|
t_uv2 = (float *)tface[target_face].uv[target_uv2];
|
|
|
|
|
|
|
|
//printf("connected UV : %f,%f & %f,%f - %f,%f & %f,%f\n", s_uv1[0], s_uv1[1], s_uv2[0], s_uv2[1], t_uv1[0], t_uv1[1], t_uv2[0], t_uv2[1]);
|
|
|
|
|
|
|
|
if (((s_uv1[0] == t_uv1[0] && s_uv1[1] == t_uv1[1]) &&
|
2012-04-28 06:31:57 +00:00
|
|
|
(s_uv2[0] == t_uv2[0] && s_uv2[1] == t_uv2[1]) ) ||
|
|
|
|
((s_uv2[0] == t_uv1[0] && s_uv2[1] == t_uv1[1]) &&
|
|
|
|
(s_uv1[0] == t_uv2[0] && s_uv1[1] == t_uv2[1]) ))
|
|
|
|
{
|
2012-05-12 16:11:34 +00:00
|
|
|
return ((px + neighX[n_index]) + w * (py + neighY[n_index]));
|
2012-04-28 06:31:57 +00:00
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* Find a point that is relatively at same edge position
|
|
|
|
* on this other face UV
|
|
|
|
*/
|
2011-06-27 07:30:58 +00:00
|
|
|
lambda = closest_to_line_v2(closest_point, pixel, tface[cPoint->face_index].uv[edge1_index], tface[cPoint->face_index].uv[edge2_index]);
|
2011-05-24 07:08:58 +00:00
|
|
|
if (lambda < 0.0f) lambda = 0.0f;
|
|
|
|
if (lambda > 1.0f) lambda = 1.0f;
|
|
|
|
|
|
|
|
sub_v2_v2v2(dir_vec, tface[target_face].uv[target_uv2], tface[target_face].uv[target_uv1]);
|
|
|
|
|
|
|
|
mul_v2_fl(dir_vec, lambda);
|
|
|
|
|
|
|
|
copy_v2_v2(pixel, tface[target_face].uv[target_uv1]);
|
|
|
|
add_v2_v2(pixel, dir_vec);
|
2011-06-27 07:30:58 +00:00
|
|
|
pixel[0] = (pixel[0] * (float)w) - 0.5f;
|
|
|
|
pixel[1] = (pixel[1] * (float)h) - 0.5f;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
|
|
|
final_pixel[0] = (int)floor(pixel[0]);
|
|
|
|
final_pixel[1] = (int)floor(pixel[1]);
|
|
|
|
|
|
|
|
/* If current pixel uv is outside of texture */
|
2012-01-24 17:28:50 +00:00
|
|
|
if (final_pixel[0] < 0 || final_pixel[0] >= w) return OUT_OF_TEXTURE;
|
|
|
|
if (final_pixel[1] < 0 || final_pixel[1] >= h) return OUT_OF_TEXTURE;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
final_index = final_pixel[0] + w * final_pixel[1];
|
2011-05-24 07:08:58 +00:00
|
|
|
|
|
|
|
/* If we ended up to our origin point ( mesh has smaller than pixel sized faces) */
|
2012-05-12 16:11:34 +00:00
|
|
|
if (final_index == (px + w * py)) return NOT_FOUND;
|
2011-05-24 07:08:58 +00:00
|
|
|
/* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
|
2012-01-24 17:28:50 +00:00
|
|
|
if (tempPoints[final_index].face_index != target_face) return NOT_FOUND;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* If final point is an "edge pixel", use it's "real" neighbor instead
|
|
|
|
*/
|
2011-06-27 07:30:58 +00:00
|
|
|
if (tempPoints[final_index].neighbour_pixel != -1) final_index = cPoint->neighbour_pixel;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
|
|
|
return final_index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* Create a surface for uv image sequence format
|
|
|
|
*/
|
Fix #36058: Displace Modifier errors using a baked Image and displace baking inconsistency between 2.67/2.68RC and previous versions
This was in fact really nasty bug, caused by multitex_nodes
function using global variable R (which is a copy of current
renderer). this variable is not initialized to anything
meaningful for until first rendering (preview or final)
happened.
Since multitex_nodes might be used outside of render pipeline,
made it so whether CM is on or off as an argument to functions
multitex_ext_safe and multitex_ext. Now multitex_nodes() is
only shall be used for stuff happening from render pipeline!
Also needed to make some changes to other places, so all the
usages of texture sampling knows for the fact whether CM is
on or off.
And one more change is related on behavior of dispalcement,
wave, warp, weightvg modifiers and smoke. They'll be always
using CM off since texture is used for influence, not for
color.
It's rather bigger patch, but it's mostly straightforward
changes, which we really need to be done.
Reviewed by Brecht, thanks!
2013-07-15 14:47:58 +00:00
|
|
|
int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
|
2011-05-24 07:08:58 +00:00
|
|
|
{
|
2011-06-16 10:41:00 +00:00
|
|
|
/* Antialias jitter point relative coords */
|
|
|
|
float jitter5sample[10] = {0.0f, 0.0f,
|
2012-05-12 16:11:34 +00:00
|
|
|
-0.2f, -0.4f,
|
|
|
|
0.2f, 0.4f,
|
|
|
|
0.4f, -0.2f,
|
|
|
|
-0.4f, 0.3f};
|
2011-07-22 18:37:30 +00:00
|
|
|
int ty;
|
2012-04-29 15:47:02 +00:00
|
|
|
int w, h;
|
2011-06-16 10:41:00 +00:00
|
|
|
int numOfFaces;
|
2012-01-11 08:51:06 +00:00
|
|
|
char uvname[MAX_CUSTOMDATA_LAYER_NAME];
|
2011-06-16 10:41:00 +00:00
|
|
|
int active_points = 0;
|
2011-06-27 07:30:58 +00:00
|
|
|
int error = 0;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
PaintSurfaceData *sData;
|
|
|
|
DynamicPaintCanvasSettings *canvas = surface->canvas;
|
|
|
|
DerivedMesh *dm = canvas->dm;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
PaintUVPoint *tempPoints = NULL;
|
|
|
|
Vec3f *tempWeights = NULL;
|
2011-06-16 10:41:00 +00:00
|
|
|
MFace *mface = NULL;
|
|
|
|
MTFace *tface = NULL;
|
2011-07-22 18:37:30 +00:00
|
|
|
Bounds2D *faceBB = NULL;
|
2011-06-27 07:30:58 +00:00
|
|
|
int *final_index;
|
2011-07-08 11:03:37 +00:00
|
|
|
int aa_samples;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-10-26 17:32:50 +00:00
|
|
|
if (!dm)
|
|
|
|
return setError(canvas, N_("Canvas mesh not updated"));
|
|
|
|
if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ)
|
|
|
|
return setError(canvas, N_("Cannot bake non-'image sequence' formats"));
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-01-24 18:29:01 +00:00
|
|
|
numOfFaces = dm->getNumTessFaces(dm);
|
2011-11-11 11:20:46 +00:00
|
|
|
mface = dm->getTessFaceArray(dm);
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-11-23 17:25:25 +00:00
|
|
|
/* get uv map */
|
2011-10-13 20:00:22 +00:00
|
|
|
CustomData_validate_layer_name(&dm->faceData, CD_MTFACE, surface->uvlayer_name, uvname);
|
2011-06-16 10:41:00 +00:00
|
|
|
tface = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, uvname);
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/* Check for validity */
|
2012-10-26 17:32:50 +00:00
|
|
|
if (!tface)
|
|
|
|
return setError(canvas, N_("No UV data on canvas"));
|
|
|
|
if (surface->image_resolution < 16 || surface->image_resolution > 8192)
|
|
|
|
return setError(canvas, N_("Invalid resolution"));
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
w = h = surface->image_resolution;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* Start generating the surface
|
|
|
|
*/
|
2011-06-16 10:41:00 +00:00
|
|
|
printf("DynamicPaint: Preparing UV surface of %ix%i pixels and %i faces.\n", w, h, numOfFaces);
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/* Init data struct */
|
|
|
|
if (surface->data) dynamicPaint_freeSurfaceData(surface);
|
|
|
|
sData = surface->data = MEM_callocN(sizeof(PaintSurfaceData), "PaintSurfaceData");
|
2012-10-26 17:32:50 +00:00
|
|
|
if (!surface->data)
|
|
|
|
return setError(canvas, N_("Not enough free memory"));
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-07-08 11:03:37 +00:00
|
|
|
aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
|
2012-05-12 16:11:34 +00:00
|
|
|
tempPoints = (struct PaintUVPoint *) MEM_callocN(w * h * sizeof(struct PaintUVPoint), "Temp PaintUVPoint");
|
|
|
|
if (!tempPoints) error = 1;
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
final_index = (int *) MEM_callocN(w * h * sizeof(int), "Temp UV Final Indexes");
|
|
|
|
if (!final_index) error = 1;
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
tempWeights = (struct Vec3f *) MEM_mallocN(w * h * aa_samples * sizeof(struct Vec3f), "Temp bWeights");
|
|
|
|
if (!tempWeights) error = 1;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* Generate a temporary bounding box array for UV faces to optimize
|
|
|
|
* the pixel-inside-a-face search.
|
|
|
|
*/
|
2011-06-27 07:30:58 +00:00
|
|
|
if (!error) {
|
2012-05-12 16:11:34 +00:00
|
|
|
faceBB = (struct Bounds2D *) MEM_mallocN(numOfFaces * sizeof(struct Bounds2D), "MPCanvasFaceBB");
|
|
|
|
if (!faceBB) error = 1;
|
2011-06-27 07:30:58 +00:00
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
if (!error)
|
2012-05-12 16:11:34 +00:00
|
|
|
for (ty = 0; ty < numOfFaces; ty++) {
|
|
|
|
int numOfVert = (mface[ty].v4) ? 4 : 3;
|
|
|
|
int i;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
copy_v2_v2(faceBB[ty].min, tface[ty].uv[0]);
|
|
|
|
copy_v2_v2(faceBB[ty].max, tface[ty].uv[0]);
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 1; i < numOfVert; i++) {
|
|
|
|
if (tface[ty].uv[i][0] < faceBB[ty].min[0]) faceBB[ty].min[0] = tface[ty].uv[i][0];
|
|
|
|
if (tface[ty].uv[i][1] < faceBB[ty].min[1]) faceBB[ty].min[1] = tface[ty].uv[i][1];
|
|
|
|
if (tface[ty].uv[i][0] > faceBB[ty].max[0]) faceBB[ty].max[0] = tface[ty].uv[i][0];
|
|
|
|
if (tface[ty].uv[i][1] > faceBB[ty].max[1]) faceBB[ty].max[1] = tface[ty].uv[i][1];
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* Loop through every pixel and check
|
|
|
|
* if pixel is uv-mapped on a canvas face.
|
|
|
|
*/
|
2011-06-27 07:30:58 +00:00
|
|
|
if (!error) {
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-04-28 06:31:57 +00:00
|
|
|
for (ty = 0; ty < h; ty++) {
|
2011-07-22 18:37:30 +00:00
|
|
|
int tx;
|
2012-04-28 06:31:57 +00:00
|
|
|
for (tx = 0; tx < w; tx++) {
|
2011-06-27 07:30:58 +00:00
|
|
|
int i, sample;
|
2012-05-12 16:11:34 +00:00
|
|
|
int index = tx + w * ty;
|
2011-06-27 07:30:58 +00:00
|
|
|
PaintUVPoint *tPoint = (&tempPoints[index]);
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
short isInside = 0; /* if point is inside a uv face */
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
float d1[2], d2[2], d3[2], point[5][2];
|
2012-04-29 15:47:02 +00:00
|
|
|
float dot00, dot01, dot02, dot11, dot12, invDenom, u, v;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
/* Init per pixel settings */
|
|
|
|
tPoint->face_index = -1;
|
|
|
|
tPoint->neighbour_pixel = -1;
|
|
|
|
tPoint->pixel_index = index;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
/* Actual pixel center, used when collision is found */
|
2011-07-22 18:37:30 +00:00
|
|
|
point[0][0] = ((float)tx + 0.5f) / w;
|
|
|
|
point[0][1] = ((float)ty + 0.5f) / h;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* A pixel middle sample isn't enough to find very narrow polygons
|
|
|
|
* So using 4 samples of each corner too
|
|
|
|
*/
|
2011-07-22 18:37:30 +00:00
|
|
|
point[1][0] = ((float)tx) / w;
|
|
|
|
point[1][1] = ((float)ty) / h;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
point[2][0] = ((float)tx + 1) / w;
|
2011-07-22 18:37:30 +00:00
|
|
|
point[2][1] = ((float)ty) / h;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
point[3][0] = ((float)tx) / w;
|
2012-05-12 16:11:34 +00:00
|
|
|
point[3][1] = ((float)ty + 1) / h;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
point[4][0] = ((float)tx + 1) / w;
|
|
|
|
point[4][1] = ((float)ty + 1) / h;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
/* Loop through samples, starting from middle point */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (sample = 0; sample < 5; sample++) {
|
2011-06-27 07:30:58 +00:00
|
|
|
|
|
|
|
/* Loop through every face in the mesh */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < numOfFaces; i++) {
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
/* 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
|
2012-05-12 16:11:34 +00:00
|
|
|
* for uv0, 1, 2 */
|
|
|
|
sub_v2_v2v2(d1, tface[i].uv[2], tface[i].uv[0]); // uv2 - uv0
|
|
|
|
sub_v2_v2v2(d2, tface[i].uv[1], tface[i].uv[0]); // uv1 - uv0
|
|
|
|
sub_v2_v2v2(d3, point[sample], tface[i].uv[0]); // point - uv0
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
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];
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2013-02-11 15:43:09 +00:00
|
|
|
invDenom = (dot00 * dot11 - dot01 * dot01);
|
|
|
|
invDenom = invDenom ? 1.0f / invDenom : 1.0f;
|
2011-06-16 10:41:00 +00:00
|
|
|
u = (dot11 * dot02 - dot01 * dot12) * invDenom;
|
|
|
|
v = (dot00 * dot12 - dot01 * dot02) * invDenom;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-06-25 07:24:48 +00:00
|
|
|
if ((u > 0) && (v > 0) && (u + v < 1)) { isInside = 1; } /* is inside a triangle */
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
/* If collision wasn't found but the face is a quad
|
2012-05-12 16:11:34 +00:00
|
|
|
* do another check for the second half */
|
2012-04-28 06:31:57 +00:00
|
|
|
if ((!isInside) && mface[i].v4) {
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
/* change d2 to test the other half */
|
2012-05-12 16:11:34 +00:00
|
|
|
sub_v2_v2v2(d2, tface[i].uv[3], tface[i].uv[0]); // uv3 - uv0
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
/* test again */
|
2012-05-12 16:11:34 +00:00
|
|
|
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];
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2013-02-11 15:43:09 +00:00
|
|
|
invDenom = (dot00 * dot11 - dot01 * dot01);
|
|
|
|
invDenom = invDenom ? 1.0f / invDenom : 1.0f;
|
2011-06-27 07:30:58 +00:00
|
|
|
u = (dot11 * dot02 - dot01 * dot12) * invDenom;
|
|
|
|
v = (dot00 * dot12 - dot01 * dot02) * invDenom;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-06-25 07:24:48 +00:00
|
|
|
if ((u > 0) && (v > 0) && (u + v < 1)) { isInside = 2; } /* is inside the second half of the quad */
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* If point was inside the face
|
|
|
|
*/
|
2011-06-27 07:30:58 +00:00
|
|
|
if (isInside != 0) {
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
float uv1co[2], uv2co[2], uv3co[2], uv[2];
|
|
|
|
int j;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
/* Get triagnle uvs */
|
2012-05-12 16:11:34 +00:00
|
|
|
if (isInside == 1) {
|
2011-10-28 14:46:09 +00:00
|
|
|
copy_v2_v2(uv1co, tface[i].uv[0]);
|
|
|
|
copy_v2_v2(uv2co, tface[i].uv[1]);
|
|
|
|
copy_v2_v2(uv3co, tface[i].uv[2]);
|
2011-06-27 07:30:58 +00:00
|
|
|
}
|
|
|
|
else {
|
2011-10-28 14:46:09 +00:00
|
|
|
copy_v2_v2(uv1co, tface[i].uv[0]);
|
|
|
|
copy_v2_v2(uv2co, tface[i].uv[2]);
|
|
|
|
copy_v2_v2(uv3co, tface[i].uv[3]);
|
2011-06-27 07:30:58 +00:00
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
/* Add b-weights per anti-aliasing sample */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (j = 0; j < aa_samples; j++) {
|
|
|
|
uv[0] = point[0][0] + jitter5sample[j * 2] / w;
|
|
|
|
uv[1] = point[0][1] + jitter5sample[j * 2 + 1] / h;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
barycentric_weights_v2(uv1co, uv2co, uv3co, uv, tempWeights[index * aa_samples + j].v);
|
2011-06-27 07:30:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set surface point face values */
|
2012-05-12 16:11:34 +00:00
|
|
|
tPoint->face_index = i; /* face index */
|
|
|
|
tPoint->quad = (isInside == 2) ? 1 : 0; /* quad or tri part*/
|
2011-06-27 07:30:58 +00:00
|
|
|
|
|
|
|
/* save vertex indexes */
|
2011-12-31 10:28:36 +00:00
|
|
|
tPoint->v1 = mface[i].v1;
|
2011-06-27 07:30:58 +00:00
|
|
|
tPoint->v2 = (isInside == 2) ? mface[i].v3 : mface[i].v2;
|
|
|
|
tPoint->v3 = (isInside == 2) ? mface[i].v4 : mface[i].v3;
|
2011-11-27 23:41:01 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
sample = 5; /* make sure we exit sample loop as well */
|
2011-06-27 07:30:58 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} /* sample loop */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* Now loop through every pixel that was left without index
|
|
|
|
* and find if they have neighboring pixels that have an index.
|
|
|
|
* If so use that polygon as pixel surface.
|
|
|
|
* (To avoid seams on uv island edges)
|
|
|
|
*/
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-04-28 06:31:57 +00:00
|
|
|
for (ty = 0; ty < h; ty++) {
|
2011-07-22 18:37:30 +00:00
|
|
|
int tx;
|
2012-04-28 06:31:57 +00:00
|
|
|
for (tx = 0; tx < w; tx++) {
|
2012-05-12 16:11:34 +00:00
|
|
|
int index = tx + w * ty;
|
2011-06-27 07:30:58 +00:00
|
|
|
PaintUVPoint *tPoint = (&tempPoints[index]);
|
|
|
|
|
2012-03-18 07:38:51 +00:00
|
|
|
/* If point isn't't on canvas mesh */
|
2011-06-27 07:30:58 +00:00
|
|
|
if (tPoint->face_index == -1) {
|
|
|
|
int u_min, u_max, v_min, v_max;
|
2012-04-29 15:47:02 +00:00
|
|
|
int u, v, ind;
|
2011-06-27 07:30:58 +00:00
|
|
|
float point[2];
|
|
|
|
|
|
|
|
/* get loop area */
|
2011-07-22 18:37:30 +00:00
|
|
|
u_min = (tx > 0) ? -1 : 0;
|
2012-05-12 16:11:34 +00:00
|
|
|
u_max = (tx < (w - 1)) ? 1 : 0;
|
2011-07-22 18:37:30 +00:00
|
|
|
v_min = (ty > 0) ? -1 : 0;
|
2012-05-12 16:11:34 +00:00
|
|
|
v_max = (ty < (h - 1)) ? 1 : 0;
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
point[0] = ((float)tx + 0.5f) / w;
|
|
|
|
point[1] = ((float)ty + 0.5f) / h;
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2012-03-01 12:20:18 +00:00
|
|
|
/* search through defined area for neighbor */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (u = u_min; u <= u_max; u++)
|
|
|
|
for (v = v_min; v <= v_max; v++) {
|
2011-06-27 07:30:58 +00:00
|
|
|
/* if not this pixel itself */
|
2012-05-12 16:11:34 +00:00
|
|
|
if (u != 0 || v != 0) {
|
|
|
|
ind = (tx + u) + w * (ty + v);
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2012-03-01 12:20:18 +00:00
|
|
|
/* if neighbor has index */
|
2011-06-27 07:30:58 +00:00
|
|
|
if (tempPoints[ind].face_index != -1) {
|
|
|
|
|
|
|
|
float uv1co[2], uv2co[2], uv3co[2], uv[2];
|
|
|
|
int i = tempPoints[ind].face_index, j;
|
|
|
|
|
|
|
|
/* Now calculate pixel data for this pixel as it was on polygon surface */
|
|
|
|
if (!tempPoints[ind].quad) {
|
2011-10-28 14:46:09 +00:00
|
|
|
copy_v2_v2(uv1co, tface[i].uv[0]);
|
|
|
|
copy_v2_v2(uv2co, tface[i].uv[1]);
|
|
|
|
copy_v2_v2(uv3co, tface[i].uv[2]);
|
2011-06-27 07:30:58 +00:00
|
|
|
}
|
|
|
|
else {
|
2011-10-28 14:46:09 +00:00
|
|
|
copy_v2_v2(uv1co, tface[i].uv[0]);
|
|
|
|
copy_v2_v2(uv2co, tface[i].uv[2]);
|
|
|
|
copy_v2_v2(uv3co, tface[i].uv[3]);
|
2011-06-27 07:30:58 +00:00
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
/* Add b-weights per anti-aliasing sample */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (j = 0; j < aa_samples; j++) {
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
uv[0] = point[0] + jitter5sample[j * 2] / w;
|
|
|
|
uv[1] = point[1] + jitter5sample[j * 2 + 1] / h;
|
|
|
|
barycentric_weights_v2(uv1co, uv2co, uv3co, uv, tempWeights[index * aa_samples + j].v);
|
2011-06-27 07:30:58 +00:00
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
/* Set values */
|
2012-05-12 16:11:34 +00:00
|
|
|
tPoint->neighbour_pixel = ind; // face index
|
|
|
|
tPoint->quad = tempPoints[ind].quad; // quad or tri
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
/* save vertex indexes */
|
2011-12-31 10:28:36 +00:00
|
|
|
tPoint->v1 = mface[i].v1;
|
2011-06-27 07:30:58 +00:00
|
|
|
tPoint->v2 = (tPoint->quad) ? mface[i].v3 : mface[i].v2;
|
|
|
|
tPoint->v3 = (tPoint->quad) ? mface[i].v4 : mface[i].v3;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
u = u_max + 1; /* make sure we exit outer loop as well */
|
2011-06-27 07:30:58 +00:00
|
|
|
break;
|
|
|
|
}
|
2012-05-12 16:11:34 +00:00
|
|
|
}
|
2011-06-27 07:30:58 +00:00
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* When base loop is over convert found neighbor indexes to real ones
|
|
|
|
* Also count the final number of active surface points
|
|
|
|
*/
|
2012-04-28 06:31:57 +00:00
|
|
|
for (ty = 0; ty < h; ty++) {
|
2011-07-22 18:37:30 +00:00
|
|
|
int tx;
|
2012-04-28 06:31:57 +00:00
|
|
|
for (tx = 0; tx < w; tx++) {
|
2012-05-12 16:11:34 +00:00
|
|
|
int index = tx + w * ty;
|
2011-06-27 07:30:58 +00:00
|
|
|
PaintUVPoint *tPoint = (&tempPoints[index]);
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
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++;
|
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-12-31 10:28:36 +00:00
|
|
|
/* Generate surface adjacency data. */
|
|
|
|
{
|
2012-05-12 16:11:34 +00:00
|
|
|
int i, cursor = 0;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
/* Create a temporary array of final indexes (before unassigned
|
2012-05-12 16:11:34 +00:00
|
|
|
* pixels have been dropped) */
|
|
|
|
for (i = 0; i < w * h; i++) {
|
2011-06-27 07:30:58 +00:00
|
|
|
if (tempPoints[i].face_index != -1) {
|
|
|
|
final_index[i] = cursor;
|
|
|
|
cursor++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* allocate memory */
|
2012-05-12 16:11:34 +00:00
|
|
|
sData->total_points = w * h;
|
2011-12-31 10:28:36 +00:00
|
|
|
dynamicPaint_initAdjacencyData(surface, 1);
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2011-07-02 18:06:39 +00:00
|
|
|
if (sData->adj_data) {
|
|
|
|
PaintAdjData *ed = sData->adj_data;
|
2011-06-27 07:30:58 +00:00
|
|
|
unsigned int n_pos = 0;
|
2012-04-28 06:31:57 +00:00
|
|
|
for (ty = 0; ty < h; ty++) {
|
2011-07-22 18:37:30 +00:00
|
|
|
int tx;
|
2012-04-28 06:31:57 +00:00
|
|
|
for (tx = 0; tx < w; tx++) {
|
2012-05-12 16:11:34 +00:00
|
|
|
int i, index = tx + w * ty;
|
2011-06-27 07:30:58 +00:00
|
|
|
|
|
|
|
if (tempPoints[index].face_index != -1) {
|
|
|
|
ed->n_index[final_index[index]] = n_pos;
|
2011-07-08 11:03:37 +00:00
|
|
|
ed->n_num[final_index[index]] = 0;
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < 8; i++) {
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2012-03-01 12:20:18 +00:00
|
|
|
/* Try to find a neighboring pixel in defined direction
|
2012-05-12 16:11:34 +00:00
|
|
|
* If not found, -1 is returned */
|
2011-07-22 18:37:30 +00:00
|
|
|
int n_target = dynamicPaint_findNeighbourPixel(tempPoints, dm, uvname, w, h, tx, ty, i);
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2012-01-24 17:28:50 +00:00
|
|
|
if (n_target >= 0) {
|
2011-06-27 07:30:58 +00:00
|
|
|
ed->n_target[n_pos] = final_index[n_target];
|
2011-07-08 11:03:37 +00:00
|
|
|
ed->n_num[final_index[index]]++;
|
2011-06-27 07:30:58 +00:00
|
|
|
n_pos++;
|
|
|
|
}
|
2012-01-24 17:28:50 +00:00
|
|
|
else if (n_target == ON_MESH_EDGE || n_target == OUT_OF_TEXTURE) {
|
|
|
|
ed->flags[final_index[index]] |= ADJ_ON_MESH_EDGE;
|
|
|
|
}
|
2011-06-27 07:30:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
/* Create final surface data without inactive points */
|
|
|
|
{
|
|
|
|
ImgSeqFormatData *f_data = MEM_callocN(sizeof(struct ImgSeqFormatData), "ImgSeqFormatData");
|
|
|
|
if (f_data) {
|
2012-05-12 16:11:34 +00:00
|
|
|
f_data->uv_p = MEM_callocN(active_points * sizeof(struct PaintUVPoint), "PaintUVPoint");
|
|
|
|
f_data->barycentricWeights = MEM_callocN(active_points * aa_samples * sizeof(struct Vec3f), "PaintUVPoint");
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
if (!f_data->uv_p || !f_data->barycentricWeights) error = 1;
|
2011-06-27 07:30:58 +00:00
|
|
|
}
|
2013-03-09 03:46:30 +00:00
|
|
|
else {
|
|
|
|
error = 1;
|
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
sData->total_points = active_points;
|
|
|
|
|
|
|
|
/* in case of allocation error, free everything */
|
|
|
|
if (error) {
|
|
|
|
if (f_data) {
|
|
|
|
if (f_data->uv_p) MEM_freeN(f_data->uv_p);
|
|
|
|
if (f_data->barycentricWeights) MEM_freeN(f_data->barycentricWeights);
|
|
|
|
MEM_freeN(f_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
int index, cursor = 0;
|
|
|
|
sData->total_points = active_points;
|
|
|
|
sData->format_data = f_data;
|
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
for (index = 0; index < (w * h); index++) {
|
2011-06-27 07:30:58 +00:00
|
|
|
if (tempPoints[index].face_index != -1) {
|
|
|
|
memcpy(&f_data->uv_p[cursor], &tempPoints[index], sizeof(PaintUVPoint));
|
2012-05-12 16:11:34 +00:00
|
|
|
memcpy(&f_data->barycentricWeights[cursor * aa_samples], &tempWeights[index * aa_samples], sizeof(Vec3f) * aa_samples);
|
2011-06-27 07:30:58 +00:00
|
|
|
cursor++;
|
|
|
|
}
|
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-10-26 17:32:50 +00:00
|
|
|
if (error == 1)
|
|
|
|
setError(canvas, N_("Not enough free memory"));
|
2011-06-27 07:30:58 +00:00
|
|
|
|
|
|
|
if (faceBB) MEM_freeN(faceBB);
|
|
|
|
if (tempPoints) MEM_freeN(tempPoints);
|
|
|
|
if (tempWeights) MEM_freeN(tempWeights);
|
|
|
|
if (final_index) MEM_freeN(final_index);
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/* Init surface type data */
|
2011-06-27 07:30:58 +00:00
|
|
|
if (!error) {
|
|
|
|
dynamicPaint_allocateSurfaceType(surface);
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
#if 0
|
|
|
|
/* -----------------------------------------------------------------
|
2012-05-16 23:37:23 +00:00
|
|
|
* For debug, output pixel statuses to the color map
|
|
|
|
* -----------------------------------------------------------------*/
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2011-06-27 07:30:58 +00:00
|
|
|
for (index = 0; index < sData->total_points; index++)
|
|
|
|
{
|
2012-05-12 16:11:34 +00:00
|
|
|
ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
|
|
|
|
PaintUVPoint *uvPoint = &((PaintUVPoint *)f_data->uv_p)[index];
|
|
|
|
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
|
|
|
|
pPoint->alpha = 1.0f;
|
2011-06-27 07:30:58 +00:00
|
|
|
|
|
|
|
/* Every pixel that is assigned as "edge pixel" gets blue color */
|
|
|
|
if (uvPoint->neighbour_pixel != -1) pPoint->color[2] = 1.0f;
|
|
|
|
/* and every pixel that finally got an polygon gets red color */
|
|
|
|
if (uvPoint->face_index != -1) pPoint->color[0] = 1.0f;
|
|
|
|
/* green color shows pixel face index hash */
|
2012-05-12 16:11:34 +00:00
|
|
|
if (uvPoint->face_index != -1) pPoint->color[1] = (float)(uvPoint->face_index % 255) / 256.0f;
|
2011-06-27 07:30:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
Fix #36058: Displace Modifier errors using a baked Image and displace baking inconsistency between 2.67/2.68RC and previous versions
This was in fact really nasty bug, caused by multitex_nodes
function using global variable R (which is a copy of current
renderer). this variable is not initialized to anything
meaningful for until first rendering (preview or final)
happened.
Since multitex_nodes might be used outside of render pipeline,
made it so whether CM is on or off as an argument to functions
multitex_ext_safe and multitex_ext. Now multitex_nodes() is
only shall be used for stuff happening from render pipeline!
Also needed to make some changes to other places, so all the
usages of texture sampling knows for the fact whether CM is
on or off.
And one more change is related on behavior of dispalcement,
wave, warp, weightvg modifiers and smoke. They'll be always
using CM off since texture is used for influence, not for
color.
It's rather bigger patch, but it's mostly straightforward
changes, which we really need to be done.
Reviewed by Brecht, thanks!
2013-07-15 14:47:58 +00:00
|
|
|
dynamicPaint_setInitialColor(scene, surface);
|
2011-06-27 07:30:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return (error == 0);
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* Outputs an image file from uv surface data.
|
|
|
|
*/
|
|
|
|
void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filename, short output_layer)
|
2011-05-24 07:08:58 +00:00
|
|
|
{
|
2011-06-16 10:41:00 +00:00
|
|
|
int index;
|
2012-05-12 16:11:34 +00:00
|
|
|
ImBuf *ibuf = NULL;
|
2011-06-16 10:41:00 +00:00
|
|
|
PaintSurfaceData *sData = surface->data;
|
2012-05-12 16:11:34 +00:00
|
|
|
ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
|
2011-10-28 14:46:09 +00:00
|
|
|
/* OpenEXR or PNG */
|
2011-11-22 00:35:26 +00:00
|
|
|
int format = (surface->image_fileformat & MOD_DPAINT_IMGFORMAT_OPENEXR) ? R_IMF_IMTYPE_OPENEXR : R_IMF_IMTYPE_PNG;
|
2011-10-28 14:46:09 +00:00
|
|
|
char output_file[FILE_MAX];
|
|
|
|
|
2012-10-26 17:32:50 +00:00
|
|
|
if (!sData->type_data) {
|
|
|
|
setError(surface->canvas, N_("Image save failed: invalid surface"));
|
|
|
|
return;
|
|
|
|
}
|
2011-10-28 14:46:09 +00:00
|
|
|
/* if selected format is openexr, but current build doesnt support one */
|
2013-12-22 14:11:10 +11:00
|
|
|
#ifndef WITH_OPENEXR
|
2011-11-22 00:35:26 +00:00
|
|
|
if (format == R_IMF_IMTYPE_OPENEXR) format = R_IMF_IMTYPE_PNG;
|
2013-12-22 14:11:10 +11:00
|
|
|
#endif
|
2011-10-28 14:46:09 +00:00
|
|
|
BLI_strncpy(output_file, filename, sizeof(output_file));
|
2012-12-23 13:57:09 +00:00
|
|
|
BKE_add_image_extension_from_type(output_file, format);
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/* Validate output file path */
|
|
|
|
BLI_path_abs(output_file, G.main->name);
|
|
|
|
BLI_make_existing_file(output_file);
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/* Init image buffer */
|
2011-10-13 20:00:22 +00:00
|
|
|
ibuf = IMB_allocImBuf(surface->image_resolution, surface->image_resolution, 32, IB_rectfloat);
|
2012-10-26 17:32:50 +00:00
|
|
|
if (ibuf == NULL) {
|
|
|
|
setError(surface->canvas, N_("Image save failed: not enough free memory"));
|
|
|
|
return;
|
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-04-28 06:31:57 +00:00
|
|
|
for (index = 0; index < sData->total_points; index++) {
|
2012-05-12 16:11:34 +00:00
|
|
|
int pos = f_data->uv_p[index].pixel_index * 4; /* image buffer position */
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/* Set values of preferred type */
|
2011-10-28 14:46:09 +00:00
|
|
|
if (output_layer == 1) {
|
|
|
|
/* wetmap */
|
|
|
|
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
|
2012-05-12 16:11:34 +00:00
|
|
|
PaintPoint *point = &((PaintPoint *)sData->type_data)[index];
|
2011-10-28 14:46:09 +00:00
|
|
|
float value = (point->wetness > 1.0f) ? 1.0f : point->wetness;
|
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
ibuf->rect_float[pos] = value;
|
|
|
|
ibuf->rect_float[pos + 1] = value;
|
|
|
|
ibuf->rect_float[pos + 2] = value;
|
|
|
|
ibuf->rect_float[pos + 3] = 1.0f;
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
}
|
2011-10-28 14:46:09 +00:00
|
|
|
else if (output_layer == 0) {
|
|
|
|
/* Paintmap */
|
|
|
|
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
|
2012-05-12 16:11:34 +00:00
|
|
|
PaintPoint *point = &((PaintPoint *)sData->type_data)[index];
|
2011-10-28 14:46:09 +00:00
|
|
|
|
2012-01-16 17:18:07 +00:00
|
|
|
/* blend wet and dry layers */
|
|
|
|
blendColors(point->color, point->alpha, point->e_color, point->e_alpha, &ibuf->rect_float[pos]);
|
2011-10-28 14:46:09 +00:00
|
|
|
|
|
|
|
/* Multiply color by alpha if enabled */
|
|
|
|
if (surface->flags & MOD_DPAINT_MULALPHA) {
|
2012-05-12 16:11:34 +00:00
|
|
|
ibuf->rect_float[pos] *= ibuf->rect_float[pos + 3];
|
|
|
|
ibuf->rect_float[pos + 1] *= ibuf->rect_float[pos + 3];
|
|
|
|
ibuf->rect_float[pos + 2] *= ibuf->rect_float[pos + 3];
|
2011-10-28 14:46:09 +00:00
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
2011-10-28 14:46:09 +00:00
|
|
|
/* displace */
|
|
|
|
else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
|
2012-05-12 16:11:34 +00:00
|
|
|
float depth = ((float *)sData->type_data)[index];
|
2011-10-28 14:46:09 +00:00
|
|
|
if (surface->depth_clamp)
|
|
|
|
depth /= surface->depth_clamp;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-10-28 14:46:09 +00:00
|
|
|
if (surface->disp_type == MOD_DPAINT_DISP_DISPLACE) {
|
2012-05-12 16:11:34 +00:00
|
|
|
depth = (0.5f - depth / 2.0f);
|
2011-10-28 14:46:09 +00:00
|
|
|
}
|
2011-10-13 20:00:22 +00:00
|
|
|
|
2011-10-28 14:46:09 +00:00
|
|
|
CLAMP(depth, 0.0f, 1.0f);
|
2011-10-13 20:00:22 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
ibuf->rect_float[pos] = depth;
|
|
|
|
ibuf->rect_float[pos + 1] = depth;
|
|
|
|
ibuf->rect_float[pos + 2] = depth;
|
|
|
|
ibuf->rect_float[pos + 3] = 1.0f;
|
2011-10-28 14:46:09 +00:00
|
|
|
}
|
|
|
|
/* waves */
|
|
|
|
else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
|
2012-05-12 16:11:34 +00:00
|
|
|
PaintWavePoint *wPoint = &((PaintWavePoint *)sData->type_data)[index];
|
2011-10-28 14:46:09 +00:00
|
|
|
float depth = wPoint->height;
|
|
|
|
if (surface->depth_clamp)
|
2012-05-12 16:11:34 +00:00
|
|
|
depth /= surface->depth_clamp;
|
|
|
|
depth = (0.5f + depth / 2.0f);
|
2011-10-28 14:46:09 +00:00
|
|
|
CLAMP(depth, 0.0f, 1.0f);
|
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
ibuf->rect_float[pos] = depth;
|
|
|
|
ibuf->rect_float[pos + 1] = depth;
|
|
|
|
ibuf->rect_float[pos + 2] = depth;
|
|
|
|
ibuf->rect_float[pos + 3] = 1.0f;
|
2011-10-28 14:46:09 +00:00
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-03-18 07:38:51 +00:00
|
|
|
/* Set output format, png in case exr isn't supported */
|
2012-05-12 16:11:34 +00:00
|
|
|
ibuf->ftype = PNG | 95;
|
2011-06-16 10:41:00 +00:00
|
|
|
#ifdef WITH_OPENEXR
|
2012-05-12 16:11:34 +00:00
|
|
|
if (format == R_IMF_IMTYPE_OPENEXR) { /* OpenEXR 32-bit float */
|
2011-10-13 20:00:22 +00:00
|
|
|
ibuf->ftype = OPENEXR | OPENEXR_COMPRESS;
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
#endif
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-10-13 20:00:22 +00:00
|
|
|
/* Save image */
|
|
|
|
IMB_saveiff(ibuf, output_file, IB_rectfloat);
|
|
|
|
IMB_freeImBuf(ibuf);
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/***************************** Material / Texture Sampling ******************************/
|
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* stores a copy of required materials to allow doing adjustments
|
2012-05-12 16:11:34 +00:00
|
|
|
* without interfering the render/preview */
|
2011-09-05 16:04:15 +00:00
|
|
|
typedef struct BrushMaterials {
|
|
|
|
Material *mat;
|
|
|
|
Material **ob_mats;
|
|
|
|
int tot;
|
|
|
|
} BrushMaterials;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* Initialize materials for brush object:
|
2012-05-12 16:11:34 +00:00
|
|
|
* Calculates inverse matrices for linked objects, updates
|
|
|
|
* volume caches etc. */
|
2011-09-05 16:04:15 +00:00
|
|
|
static void dynamicPaint_updateBrushMaterials(Object *brushOb, Material *ui_mat, Scene *scene, BrushMaterials *bMats)
|
|
|
|
{
|
|
|
|
/* Calculate inverse transformation matrix
|
2012-05-12 16:11:34 +00:00
|
|
|
* for this object */
|
2011-09-05 16:04:15 +00:00
|
|
|
invert_m4_m4(brushOb->imat, brushOb->obmat);
|
|
|
|
copy_m4_m4(brushOb->imat_ren, brushOb->imat);
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* Now process every material linked to this brush object */
|
|
|
|
if ((ui_mat == NULL) && brushOb->mat && brushOb->totcol) {
|
2012-05-12 16:11:34 +00:00
|
|
|
int i, tot = (*give_totcolp(brushOb));
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* allocate material pointer array */
|
2011-10-22 16:16:14 +00:00
|
|
|
if (tot) {
|
2012-05-12 16:11:34 +00:00
|
|
|
bMats->ob_mats = MEM_callocN(sizeof(Material *) * (tot), "BrushMaterials");
|
|
|
|
for (i = 0; i < tot; i++) {
|
|
|
|
bMats->ob_mats[i] = RE_init_sample_material(give_current_material(brushOb, (i + 1)), scene);
|
2011-10-22 16:16:14 +00:00
|
|
|
}
|
2011-09-05 16:04:15 +00:00
|
|
|
}
|
|
|
|
bMats->tot = tot;
|
|
|
|
}
|
|
|
|
else {
|
2011-10-22 16:16:14 +00:00
|
|
|
bMats->mat = RE_init_sample_material(ui_mat, scene);
|
2011-09-05 16:04:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* free all data allocated by dynamicPaint_updateBrushMaterials() */
|
|
|
|
static void dynamicPaint_freeBrushMaterials(BrushMaterials *bMats)
|
|
|
|
{
|
|
|
|
/* Now process every material linked to this brush object */
|
|
|
|
if (bMats->ob_mats) {
|
|
|
|
int i;
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < bMats->tot; i++) {
|
2011-10-22 16:16:14 +00:00
|
|
|
RE_free_sample_material(bMats->ob_mats[i]);
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
2011-09-05 16:04:15 +00:00
|
|
|
MEM_freeN(bMats->ob_mats);
|
|
|
|
}
|
2011-10-22 16:16:14 +00:00
|
|
|
else if (bMats->mat) {
|
|
|
|
RE_free_sample_material(bMats->mat);
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* Get material diffuse color and alpha (including linked textures) in given coordinates
|
|
|
|
*/
|
2012-12-23 01:18:35 +00:00
|
|
|
static void dynamicPaint_doMaterialTex(BrushMaterials *bMats, float color[3], float *alpha, Object *brushOb,
|
|
|
|
const float volume_co[3], const float surface_co[3],
|
|
|
|
int faceIndex, short isQuad, DerivedMesh *orcoDm)
|
2011-05-24 07:08:58 +00:00
|
|
|
{
|
2011-09-05 16:04:15 +00:00
|
|
|
Material *mat = bMats->mat;
|
2011-11-11 11:20:46 +00:00
|
|
|
MFace *mface = orcoDm->getTessFaceArray(orcoDm);
|
2011-09-05 16:04:15 +00:00
|
|
|
|
|
|
|
/* If no material defined, use the one assigned to the mesh face */
|
|
|
|
if (mat == NULL) {
|
|
|
|
if (bMats->ob_mats) {
|
|
|
|
int mat_nr = mface[faceIndex].mat_nr;
|
|
|
|
if (mat_nr >= (*give_totcolp(brushOb))) return;
|
|
|
|
mat = bMats->ob_mats[mat_nr];
|
2012-05-12 16:11:34 +00:00
|
|
|
if (mat == NULL) return; /* No material assigned */
|
2011-09-05 16:04:15 +00:00
|
|
|
}
|
2013-03-09 03:46:30 +00:00
|
|
|
else {
|
|
|
|
return;
|
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
2011-09-05 16:04:15 +00:00
|
|
|
|
2011-10-22 16:16:14 +00:00
|
|
|
RE_sample_material_color(mat, color, alpha, volume_co, surface_co, faceIndex, isQuad, orcoDm, brushOb);
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/***************************** Ray / Nearest Point Utils ******************************/
|
|
|
|
|
|
|
|
|
|
|
|
/* A modified callback to bvh tree raycast. The tree must bust have been built using bvhtree_from_mesh_faces.
|
2012-05-12 16:11:34 +00:00
|
|
|
* 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.
|
|
|
|
*/
|
2011-06-16 10:41:00 +00:00
|
|
|
static void mesh_faces_spherecast_dp(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
|
|
|
|
{
|
2012-05-12 16:11:34 +00:00
|
|
|
const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata;
|
|
|
|
MVert *vert = data->vert;
|
2011-06-16 10:41:00 +00:00
|
|
|
MFace *face = data->face + index;
|
|
|
|
short quad = 0;
|
|
|
|
|
|
|
|
float *t0, *t1, *t2, *t3;
|
2012-05-12 16:11:34 +00:00
|
|
|
t0 = vert[face->v1].co;
|
|
|
|
t1 = vert[face->v2].co;
|
|
|
|
t2 = vert[face->v3].co;
|
|
|
|
t3 = face->v4 ? vert[face->v4].co : NULL;
|
2011-06-16 10:41:00 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
do {
|
2011-10-28 14:46:09 +00:00
|
|
|
float dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, t1, t2);
|
2011-06-16 10:41:00 +00:00
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
if (dist >= 0 && dist < hit->dist) {
|
2011-06-16 10:41:00 +00:00
|
|
|
hit->index = index;
|
|
|
|
hit->dist = dist;
|
|
|
|
hit->no[0] = (quad) ? 1.0f : 0.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
t1 = t2;
|
|
|
|
t2 = t3;
|
|
|
|
t3 = NULL;
|
|
|
|
quad = 1;
|
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
} while (t2);
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* A modified callback to bvh tree nearest point. The tree must bust have been built using bvhtree_from_mesh_faces.
|
2012-05-12 16:11:34 +00:00
|
|
|
* 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
|
|
|
|
*/
|
2012-04-28 08:29:20 +00:00
|
|
|
static void mesh_faces_nearest_point_dp(void *userdata, int index, const float co[3], BVHTreeNearest *nearest)
|
2011-06-16 10:41:00 +00:00
|
|
|
{
|
2012-05-12 16:11:34 +00:00
|
|
|
const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata;
|
|
|
|
MVert *vert = data->vert;
|
2011-06-16 10:41:00 +00:00
|
|
|
MFace *face = data->face + index;
|
|
|
|
short quad = 0;
|
|
|
|
|
|
|
|
float *t0, *t1, *t2, *t3;
|
2012-05-12 16:11:34 +00:00
|
|
|
t0 = vert[face->v1].co;
|
|
|
|
t1 = vert[face->v2].co;
|
|
|
|
t2 = vert[face->v3].co;
|
|
|
|
t3 = face->v4 ? vert[face->v4].co : NULL;
|
2011-06-16 10:41:00 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
do {
|
2011-06-16 10:41:00 +00:00
|
|
|
float nearest_tmp[3], dist;
|
|
|
|
int vertex, edge;
|
|
|
|
|
|
|
|
dist = nearest_point_in_tri_surface(t0, t1, t2, co, &vertex, &edge, nearest_tmp);
|
2012-04-28 06:31:57 +00:00
|
|
|
if (dist < nearest->dist) {
|
2011-06-16 10:41:00 +00:00
|
|
|
nearest->index = index;
|
|
|
|
nearest->dist = dist;
|
2011-10-28 14:46:09 +00:00
|
|
|
copy_v3_v3(nearest->co, nearest_tmp);
|
2011-06-16 10:41:00 +00:00
|
|
|
nearest->no[0] = (quad) ? 1.0f : 0.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
t1 = t2;
|
|
|
|
t2 = t3;
|
|
|
|
t3 = NULL;
|
|
|
|
quad = 1;
|
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
} while (t2);
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/***************************** Brush Painting Calls ******************************/
|
2011-06-16 10:41:00 +00:00
|
|
|
|
2012-09-26 20:05:38 +00:00
|
|
|
/**
|
|
|
|
* Mix color values to canvas point.
|
2012-05-12 16:11:34 +00:00
|
|
|
*
|
2012-09-26 20:05:38 +00:00
|
|
|
* \param surface canvas surface
|
|
|
|
* \param index surface point index
|
|
|
|
* \param paintFlags paint object flags
|
|
|
|
* \param paintColor,Alpha,Wetness to be mixed paint values
|
|
|
|
* \param timescale value used to adjust time dependent
|
|
|
|
* operations when using substeps
|
2012-05-12 16:11:34 +00:00
|
|
|
*/
|
2012-05-12 22:13:38 +00:00
|
|
|
static void dynamicPaint_mixPaintColors(DynamicPaintSurface *surface, int index, int paintFlags,
|
|
|
|
const float paintColor[3], float *paintAlpha, float *paintWetness, float *timescale)
|
2011-05-24 07:08:58 +00:00
|
|
|
{
|
2012-05-12 16:11:34 +00:00
|
|
|
PaintPoint *pPoint = &((PaintPoint *)surface->data->type_data)[index];
|
2011-05-24 07:08:58 +00:00
|
|
|
|
|
|
|
/* Add paint */
|
|
|
|
if (!(paintFlags & MOD_DPAINT_ERASE)) {
|
2011-11-02 11:32:22 +00:00
|
|
|
float mix[4];
|
2011-06-27 07:30:58 +00:00
|
|
|
float temp_alpha = (*paintAlpha) * ((paintFlags & MOD_DPAINT_ABS_ALPHA) ? 1.0f : (*timescale));
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
/* mix brush color with wet layer color */
|
2011-10-31 13:01:06 +00:00
|
|
|
blendColors(pPoint->e_color, pPoint->e_alpha, paintColor, temp_alpha, mix);
|
|
|
|
copy_v3_v3(pPoint->e_color, mix);
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-11-02 11:32:22 +00:00
|
|
|
/* mix wetness and alpha depending on selected alpha mode */
|
2011-05-24 07:08:58 +00:00
|
|
|
if (paintFlags & MOD_DPAINT_ABS_ALPHA) {
|
2011-11-02 11:32:22 +00:00
|
|
|
/* update values to the brush level unless theyre higher already */
|
2011-06-16 10:41:00 +00:00
|
|
|
if (pPoint->e_alpha < (*paintAlpha)) pPoint->e_alpha = (*paintAlpha);
|
2011-11-02 11:32:22 +00:00
|
|
|
if (pPoint->wetness < (*paintWetness)) pPoint->wetness = (*paintWetness);
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
|
|
|
else {
|
2011-11-02 11:32:22 +00:00
|
|
|
float wetness = (*paintWetness);
|
|
|
|
CLAMP(wetness, 0.0f, 1.0f);
|
2011-10-31 13:01:06 +00:00
|
|
|
pPoint->e_alpha = mix[3];
|
2012-05-12 16:11:34 +00:00
|
|
|
pPoint->wetness = pPoint->wetness * (1.0f - wetness) + wetness;
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
if (pPoint->wetness < MIN_WETNESS) pPoint->wetness = MIN_WETNESS;
|
2011-11-02 11:32:22 +00:00
|
|
|
|
2011-10-28 14:46:09 +00:00
|
|
|
pPoint->state = DPAINT_PAINT_NEW;
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
|
|
|
/* Erase paint */
|
|
|
|
else {
|
|
|
|
float a_ratio, a_highest;
|
|
|
|
float wetness;
|
|
|
|
float invFact = 1.0f - (*paintAlpha);
|
|
|
|
|
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* Make highest alpha to match erased value
|
|
|
|
* but maintain alpha ratio
|
|
|
|
*/
|
2011-05-24 07:08:58 +00:00
|
|
|
if (paintFlags & MOD_DPAINT_ABS_ALPHA) {
|
2011-06-16 10:41:00 +00:00
|
|
|
a_highest = (pPoint->e_alpha > pPoint->alpha) ? pPoint->e_alpha : pPoint->alpha;
|
2011-05-24 07:08:58 +00:00
|
|
|
if (a_highest > invFact) {
|
|
|
|
a_ratio = invFact / a_highest;
|
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
pPoint->e_alpha *= a_ratio;
|
|
|
|
pPoint->alpha *= a_ratio;
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2011-06-16 10:41:00 +00:00
|
|
|
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;
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
wetness = (1.0f - (*paintWetness)) * pPoint->e_alpha;
|
|
|
|
if (pPoint->wetness > wetness) pPoint->wetness = wetness;
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* applies given brush intersection value for wave surface */
|
2011-07-02 18:06:39 +00:00
|
|
|
static void dynamicPaint_mixWaveHeight(PaintWavePoint *wPoint, DynamicPaintBrushSettings *brush, float isect_height)
|
|
|
|
{
|
2011-11-16 18:32:28 +00:00
|
|
|
float isect_change = isect_height - wPoint->brush_isect;
|
2011-07-02 18:06:39 +00:00
|
|
|
int hit = 0;
|
2011-11-16 18:32:28 +00:00
|
|
|
/* intersection marked regardless of brush type or hit */
|
|
|
|
wPoint->brush_isect = isect_height;
|
|
|
|
wPoint->state = DPAINT_WAVE_ISECT_CHANGED;
|
|
|
|
|
2011-07-02 18:06:39 +00:00
|
|
|
isect_height *= brush->wave_factor;
|
|
|
|
|
|
|
|
/* determine hit depending on wave_factor */
|
|
|
|
if (brush->wave_factor > 0.0f && wPoint->height > isect_height)
|
|
|
|
hit = 1;
|
|
|
|
else if (brush->wave_factor < 0.0f && wPoint->height < isect_height)
|
|
|
|
hit = 1;
|
|
|
|
|
|
|
|
if (hit) {
|
|
|
|
if (brush->wave_type == MOD_DPAINT_WAVEB_DEPTH) {
|
|
|
|
wPoint->height = isect_height;
|
2011-10-28 14:46:09 +00:00
|
|
|
wPoint->state = DPAINT_WAVE_OBSTACLE;
|
2011-07-02 18:06:39 +00:00
|
|
|
wPoint->velocity = 0.0f;
|
|
|
|
}
|
|
|
|
else if (brush->wave_type == MOD_DPAINT_WAVEB_FORCE)
|
|
|
|
wPoint->velocity = isect_height;
|
|
|
|
else if (brush->wave_type == MOD_DPAINT_WAVEB_REFLECT)
|
2011-10-28 14:46:09 +00:00
|
|
|
wPoint->state = DPAINT_WAVE_REFLECT_ONLY;
|
2011-11-16 18:32:28 +00:00
|
|
|
else if (brush->wave_type == MOD_DPAINT_WAVEB_CHANGE) {
|
|
|
|
if (isect_change < 0.0f)
|
2012-05-12 16:11:34 +00:00
|
|
|
wPoint->height += isect_change * brush->wave_factor;
|
2011-11-16 18:32:28 +00:00
|
|
|
}
|
2011-07-02 18:06:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-08 11:03:37 +00:00
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* add brush results to the surface data depending on surface type
|
|
|
|
*/
|
2011-08-03 18:31:48 +00:00
|
|
|
static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned int index, DynamicPaintBrushSettings *brush,
|
2012-05-12 16:11:34 +00:00
|
|
|
float paint[3], float influence, float depth, float vel_factor, float timescale)
|
2011-07-08 11:03:37 +00:00
|
|
|
{
|
2012-05-12 16:11:34 +00:00
|
|
|
PaintSurfaceData *sData = surface->data;
|
|
|
|
float strength;
|
|
|
|
|
|
|
|
/* apply influence scale */
|
|
|
|
influence *= surface->influence_scale;
|
|
|
|
depth *= surface->influence_scale;
|
|
|
|
|
|
|
|
strength = influence * brush->alpha;
|
|
|
|
CLAMP(strength, 0.0f, 1.0f);
|
|
|
|
|
|
|
|
/* Sample velocity colorband if required */
|
|
|
|
if (brush->flags & (MOD_DPAINT_VELOCITY_ALPHA | MOD_DPAINT_VELOCITY_COLOR | MOD_DPAINT_VELOCITY_DEPTH)) {
|
|
|
|
float coba_res[4];
|
|
|
|
vel_factor /= brush->max_velocity;
|
|
|
|
CLAMP(vel_factor, 0.0f, 1.0f);
|
|
|
|
|
|
|
|
if (do_colorband(brush->vel_ramp, vel_factor, coba_res)) {
|
|
|
|
if (brush->flags & MOD_DPAINT_VELOCITY_COLOR) {
|
|
|
|
paint[0] = coba_res[0];
|
|
|
|
paint[1] = coba_res[1];
|
|
|
|
paint[2] = coba_res[2];
|
2011-08-03 18:31:48 +00:00
|
|
|
}
|
2012-05-12 16:11:34 +00:00
|
|
|
if (brush->flags & MOD_DPAINT_VELOCITY_ALPHA)
|
|
|
|
strength *= coba_res[3];
|
|
|
|
if (brush->flags & MOD_DPAINT_VELOCITY_DEPTH)
|
|
|
|
depth *= coba_res[3];
|
2011-08-03 18:31:48 +00:00
|
|
|
}
|
2012-05-12 16:11:34 +00:00
|
|
|
}
|
2011-07-08 11:03:37 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
/* mix paint surface */
|
|
|
|
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
|
2011-07-08 11:03:37 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
float paintWetness = brush->wetness * strength;
|
|
|
|
float paintAlpha = strength;
|
2011-07-08 11:03:37 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
dynamicPaint_mixPaintColors(surface, index, brush->flags, paint, &paintAlpha, &paintWetness, ×cale);
|
2011-07-08 11:03:37 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
}
|
|
|
|
/* displace surface */
|
|
|
|
else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
|
|
|
|
float *value = (float *)sData->type_data;
|
2011-08-05 09:31:35 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
if (surface->flags & MOD_DPAINT_DISP_INCREMENTAL)
|
|
|
|
depth = value[index] + depth;
|
2011-08-05 09:31:35 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
if (surface->depth_clamp) {
|
|
|
|
CLAMP(depth, 0.0f - surface->depth_clamp, surface->depth_clamp);
|
2011-07-08 11:03:37 +00:00
|
|
|
}
|
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
if (brush->flags & MOD_DPAINT_ERASE) {
|
|
|
|
value[index] *= (1.0f - strength);
|
|
|
|
if (value[index] < 0.0f) value[index] = 0.0f;
|
2011-07-08 11:03:37 +00:00
|
|
|
}
|
2012-05-12 16:11:34 +00:00
|
|
|
else {
|
|
|
|
if (value[index] < depth) value[index] = depth;
|
2011-07-08 11:03:37 +00:00
|
|
|
}
|
2012-05-12 16:11:34 +00:00
|
|
|
}
|
|
|
|
/* vertex weight group surface */
|
|
|
|
else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
|
|
|
|
float *value = (float *)sData->type_data;
|
2011-08-03 18:31:48 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
if (brush->flags & MOD_DPAINT_ERASE) {
|
|
|
|
value[index] *= (1.0f - strength);
|
|
|
|
if (value[index] < 0.0f) value[index] = 0.0f;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (value[index] < strength) value[index] = strength;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* wave surface */
|
|
|
|
else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
|
|
|
|
if (brush->wave_clamp) {
|
|
|
|
CLAMP(depth, 0.0f - brush->wave_clamp, brush->wave_clamp);
|
2011-08-03 18:31:48 +00:00
|
|
|
}
|
2012-05-12 16:11:34 +00:00
|
|
|
|
|
|
|
dynamicPaint_mixWaveHeight(&((PaintWavePoint *)sData->type_data)[index],
|
|
|
|
brush, 0.0f - depth);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* doing velocity based painting */
|
|
|
|
if (sData->bData->brush_velocity) {
|
|
|
|
sData->bData->brush_velocity[index * 4 + 3] *= influence;
|
|
|
|
}
|
2011-07-08 11:03:37 +00:00
|
|
|
}
|
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* checks whether surface and brush bounds intersect depending on brush type */
|
2012-01-16 17:18:07 +00:00
|
|
|
static int meshBrush_boundsIntersect(Bounds3D *b1, Bounds3D *b2, DynamicPaintBrushSettings *brush, float brush_radius)
|
2011-07-22 18:37:30 +00:00
|
|
|
{
|
|
|
|
if (brush->collision == MOD_DPAINT_COL_VOLUME)
|
|
|
|
return boundsIntersect(b1, b2);
|
|
|
|
else if (brush->collision == MOD_DPAINT_COL_DIST || brush->collision == MOD_DPAINT_COL_VOLDIST)
|
2012-01-16 17:18:07 +00:00
|
|
|
return boundsIntersectDist(b1, b2, brush_radius);
|
2011-07-22 18:37:30 +00:00
|
|
|
else return 1;
|
|
|
|
}
|
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
/* calculate velocity for mesh vertices */
|
|
|
|
static void dynamicPaint_brushMeshCalculateVelocity(Scene *scene, Object *ob, DynamicPaintBrushSettings *brush, Vec3f **brushVel, float timescale)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
float prev_obmat[4][4];
|
|
|
|
DerivedMesh *dm_p, *dm_c;
|
|
|
|
MVert *mvert_p, *mvert_c;
|
|
|
|
int numOfVerts_p, numOfVerts_c;
|
|
|
|
|
|
|
|
float cur_sfra = scene->r.subframe;
|
|
|
|
int cur_fra = scene->r.cfra;
|
|
|
|
float prev_sfra = cur_sfra - timescale;
|
|
|
|
int prev_fra = cur_fra;
|
|
|
|
|
|
|
|
if (prev_sfra < 0.0f) {
|
|
|
|
prev_sfra += 1.0f;
|
|
|
|
prev_fra = cur_fra - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* previous frame dm */
|
|
|
|
scene->r.cfra = prev_fra;
|
|
|
|
scene->r.subframe = prev_sfra;
|
|
|
|
|
2013-03-22 17:08:55 +00:00
|
|
|
subframe_updateObject(scene, ob, UPDATE_EVERYTHING, SUBFRAME_RECURSION, BKE_scene_frame_get(scene));
|
2012-01-29 21:59:47 +00:00
|
|
|
dm_p = CDDM_copy(brush->dm);
|
2011-08-03 18:31:48 +00:00
|
|
|
numOfVerts_p = dm_p->getNumVerts(dm_p);
|
|
|
|
mvert_p = dm_p->getVertArray(dm_p);
|
|
|
|
copy_m4_m4(prev_obmat, ob->obmat);
|
|
|
|
|
|
|
|
/* current frame dm */
|
|
|
|
scene->r.cfra = cur_fra;
|
|
|
|
scene->r.subframe = cur_sfra;
|
|
|
|
|
2013-03-22 17:08:55 +00:00
|
|
|
subframe_updateObject(scene, ob, UPDATE_EVERYTHING, SUBFRAME_RECURSION, BKE_scene_frame_get(scene));
|
2011-08-03 18:31:48 +00:00
|
|
|
dm_c = brush->dm;
|
|
|
|
numOfVerts_c = dm_c->getNumVerts(dm_c);
|
|
|
|
mvert_c = dm_p->getVertArray(dm_c);
|
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
(*brushVel) = (struct Vec3f *) MEM_mallocN(numOfVerts_c * sizeof(Vec3f), "Dynamic Paint brush velocity");
|
2011-08-03 18:31:48 +00:00
|
|
|
if (!(*brushVel)) return;
|
|
|
|
|
|
|
|
/* if mesh is constructive -> num of verts has changed,
|
2012-05-12 16:11:34 +00:00
|
|
|
* only use current frame derived mesh */
|
2011-08-03 18:31:48 +00:00
|
|
|
if (numOfVerts_p != numOfVerts_c)
|
|
|
|
mvert_p = mvert_c;
|
|
|
|
|
|
|
|
/* calculate speed */
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < numOfVerts_c; i++) {
|
2011-08-03 18:31:48 +00:00
|
|
|
float p1[3], p2[3];
|
|
|
|
|
2011-10-28 14:46:09 +00:00
|
|
|
copy_v3_v3(p1, mvert_p[i].co);
|
2011-08-03 18:31:48 +00:00
|
|
|
mul_m4_v3(prev_obmat, p1);
|
|
|
|
|
2011-10-28 14:46:09 +00:00
|
|
|
copy_v3_v3(p2, mvert_c[i].co);
|
2011-08-03 18:31:48 +00:00
|
|
|
mul_m4_v3(ob->obmat, p2);
|
|
|
|
|
2011-10-28 14:46:09 +00:00
|
|
|
sub_v3_v3v3((*brushVel)[i].v, p2, p1);
|
2012-05-12 16:11:34 +00:00
|
|
|
mul_v3_fl((*brushVel)[i].v, 1.0f / timescale);
|
2011-08-03 18:31:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
dm_p->release(dm_p);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* calculate velocity for object center point */
|
2011-11-10 13:00:27 +00:00
|
|
|
static void dynamicPaint_brushObjectCalculateVelocity(Scene *scene, Object *ob, Vec3f *brushVel, float timescale)
|
2011-08-03 18:31:48 +00:00
|
|
|
{
|
|
|
|
float prev_obmat[4][4];
|
|
|
|
float cur_loc[3] = {0.0f}, prev_loc[3] = {0.0f};
|
|
|
|
|
|
|
|
float cur_sfra = scene->r.subframe;
|
|
|
|
int cur_fra = scene->r.cfra;
|
|
|
|
float prev_sfra = cur_sfra - timescale;
|
|
|
|
int prev_fra = cur_fra;
|
|
|
|
|
|
|
|
if (prev_sfra < 0.0f) {
|
|
|
|
prev_sfra += 1.0f;
|
|
|
|
prev_fra = cur_fra - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* previous frame dm */
|
|
|
|
scene->r.cfra = prev_fra;
|
|
|
|
scene->r.subframe = prev_sfra;
|
2013-03-22 17:08:55 +00:00
|
|
|
subframe_updateObject(scene, ob, 0, SUBFRAME_RECURSION, BKE_scene_frame_get(scene));
|
2011-08-03 18:31:48 +00:00
|
|
|
copy_m4_m4(prev_obmat, ob->obmat);
|
|
|
|
|
|
|
|
/* current frame dm */
|
|
|
|
scene->r.cfra = cur_fra;
|
|
|
|
scene->r.subframe = cur_sfra;
|
2013-03-22 17:08:55 +00:00
|
|
|
subframe_updateObject(scene, ob, 0, SUBFRAME_RECURSION, BKE_scene_frame_get(scene));
|
2011-08-03 18:31:48 +00:00
|
|
|
|
|
|
|
/* calculate speed */
|
|
|
|
mul_m4_v3(prev_obmat, prev_loc);
|
|
|
|
mul_m4_v3(ob->obmat, cur_loc);
|
|
|
|
|
2011-10-28 14:46:09 +00:00
|
|
|
sub_v3_v3v3(brushVel->v, cur_loc, prev_loc);
|
2012-05-12 16:11:34 +00:00
|
|
|
mul_v3_fl(brushVel->v, 1.0f / timescale);
|
2011-08-03 18:31:48 +00:00
|
|
|
}
|
|
|
|
|
2011-05-24 07:08:58 +00:00
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* Paint a brush object mesh to the surface
|
|
|
|
*/
|
2011-11-10 12:28:26 +00:00
|
|
|
static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
|
|
|
|
DynamicPaintBrushSettings *brush,
|
|
|
|
Object *brushOb,
|
|
|
|
BrushMaterials *bMats,
|
|
|
|
Scene *scene,
|
|
|
|
float timescale)
|
2011-05-24 07:08:58 +00:00
|
|
|
{
|
2011-07-22 18:37:30 +00:00
|
|
|
PaintSurfaceData *sData = surface->data;
|
|
|
|
PaintBakeData *bData = sData->bData;
|
2011-05-24 07:08:58 +00:00
|
|
|
DerivedMesh *dm = NULL;
|
2011-08-03 18:31:48 +00:00
|
|
|
Vec3f *brushVelocity = NULL;
|
2011-05-24 07:08:58 +00:00
|
|
|
MVert *mvert = NULL;
|
|
|
|
MFace *mface = NULL;
|
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
if (brush->flags & MOD_DPAINT_USES_VELOCITY)
|
|
|
|
dynamicPaint_brushMeshCalculateVelocity(scene, brushOb, brush, &brushVelocity, timescale);
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
if (!brush->dm) return 0;
|
2011-05-24 07:08:58 +00:00
|
|
|
{
|
2013-08-07 03:36:05 +00:00
|
|
|
BVHTreeFromMesh treeData = {NULL};
|
2011-09-10 08:55:44 +00:00
|
|
|
float avg_brushNor[3] = {0.0f};
|
2012-01-16 17:18:07 +00:00
|
|
|
float brush_radius = brush->paint_distance * surface->radius_scale;
|
2011-05-24 07:08:58 +00:00
|
|
|
int numOfVerts;
|
|
|
|
int ii;
|
2011-09-05 16:04:15 +00:00
|
|
|
Bounds3D mesh_bb = {0};
|
|
|
|
VolumeGrid *grid = bData->grid;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-01-29 21:59:47 +00:00
|
|
|
dm = CDDM_copy(brush->dm);
|
2011-05-24 07:08:58 +00:00
|
|
|
mvert = dm->getVertArray(dm);
|
2011-11-11 11:20:46 +00:00
|
|
|
mface = dm->getTessFaceArray(dm);
|
2011-05-24 07:08:58 +00:00
|
|
|
numOfVerts = dm->getNumVerts(dm);
|
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* Transform collider vertices to global space
|
2012-05-12 16:11:34 +00:00
|
|
|
* (Faster than transforming per surface point
|
|
|
|
* coordinates and normals to object space) */
|
|
|
|
for (ii = 0; ii < numOfVerts; ii++) {
|
2011-06-16 10:41:00 +00:00
|
|
|
mul_m4_v3(brushOb->obmat, mvert[ii].co);
|
2011-09-05 16:04:15 +00:00
|
|
|
boundInsert(&mesh_bb, mvert[ii].co);
|
2011-09-10 08:55:44 +00:00
|
|
|
|
2012-01-24 17:28:50 +00:00
|
|
|
/* for proximity project calculate average normal */
|
|
|
|
if (brush->flags & MOD_DPAINT_PROX_PROJECT && brush->collision != MOD_DPAINT_COL_VOLUME) {
|
2011-09-10 08:55:44 +00:00
|
|
|
float nor[3];
|
|
|
|
normal_short_to_float_v3(nor, mvert[ii].no);
|
|
|
|
mul_mat3_m4_v3(brushOb->obmat, nor);
|
|
|
|
normalize_v3(nor);
|
|
|
|
|
2011-10-28 14:46:09 +00:00
|
|
|
add_v3_v3(avg_brushNor, nor);
|
2011-09-10 08:55:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-24 17:28:50 +00:00
|
|
|
if (brush->flags & MOD_DPAINT_PROX_PROJECT && brush->collision != MOD_DPAINT_COL_VOLUME) {
|
2012-05-12 16:11:34 +00:00
|
|
|
mul_v3_fl(avg_brushNor, 1.0f / (float)numOfVerts);
|
2011-09-10 08:55:44 +00:00
|
|
|
/* instead of null vector use positive z */
|
2012-04-29 15:47:02 +00:00
|
|
|
if (!(MIN3(avg_brushNor[0], avg_brushNor[1], avg_brushNor[2])))
|
2011-09-10 08:55:44 +00:00
|
|
|
avg_brushNor[2] = 1.0f;
|
|
|
|
else
|
|
|
|
normalize_v3(avg_brushNor);
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
/* check bounding box collision */
|
2012-05-12 16:11:34 +00:00
|
|
|
if (grid && meshBrush_boundsIntersect(&grid->grid_bounds, &mesh_bb, brush, brush_radius)) {
|
|
|
|
/* Build a bvh tree from transformed vertices */
|
|
|
|
if (bvhtree_from_mesh_faces(&treeData, dm, 0.0f, 4, 8)) {
|
|
|
|
int c_index;
|
|
|
|
int total_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
|
|
|
|
|
|
|
|
/* loop through space partitioning grid */
|
|
|
|
for (c_index = 0; c_index < total_cells; c_index++) {
|
|
|
|
int id;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
/* check grid cell bounding box */
|
|
|
|
if (!grid->s_num[c_index] || !meshBrush_boundsIntersect(&grid->bounds[c_index], &mesh_bb, brush, brush_radius))
|
|
|
|
continue;
|
2011-07-08 11:03:37 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
/* loop through cell points and process brush */
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-05-12 16:11:34 +00:00
|
|
|
for (id = 0; id < grid->s_num[c_index]; id++) {
|
|
|
|
int index = grid->t_index[grid->s_pos[c_index] + id];
|
|
|
|
int ss, samples = bData->s_num[index];
|
|
|
|
float total_sample = (float)samples;
|
|
|
|
float brushStrength = 0.0f; /* brush influence factor */
|
|
|
|
float depth = 0.0f; /* brush intersection depth */
|
|
|
|
float velocity_val = 0.0f;
|
|
|
|
|
|
|
|
float paintColor[3] = {0.0f};
|
|
|
|
int numOfHits = 0;
|
|
|
|
|
|
|
|
/* for image sequence anti-aliasing, use gaussian factors */
|
2011-07-08 11:03:37 +00:00
|
|
|
if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
|
2012-05-12 16:11:34 +00:00
|
|
|
total_sample = gaussianTotal;
|
2011-08-03 18:31:48 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
/* Supersampling */
|
|
|
|
for (ss = 0; ss < samples; ss++) {
|
|
|
|
|
|
|
|
float ray_start[3], ray_dir[3];
|
|
|
|
float sample_factor = 0.0f;
|
|
|
|
float sampleStrength = 0.0f;
|
|
|
|
BVHTreeRayHit hit;
|
|
|
|
BVHTreeNearest nearest;
|
|
|
|
short hit_found = 0;
|
|
|
|
|
|
|
|
/* volume sample */
|
|
|
|
float volume_factor = 0.0f;
|
|
|
|
/* proximity sample */
|
|
|
|
float proximity_factor = 0.0f;
|
|
|
|
float prox_colorband[4] = {0.0f};
|
|
|
|
int inner_proximity = (brush->flags & MOD_DPAINT_INVERSE_PROX &&
|
|
|
|
brush->collision == MOD_DPAINT_COL_VOLDIST);
|
|
|
|
|
|
|
|
/* hit data */
|
|
|
|
float hitCoord[3];
|
|
|
|
int hitFace = -1;
|
|
|
|
short hitQuad = 0;
|
|
|
|
|
|
|
|
/* Supersampling factor */
|
|
|
|
if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
|
|
|
|
sample_factor = gaussianFactors[ss];
|
|
|
|
else
|
|
|
|
sample_factor = 1.0f;
|
|
|
|
|
|
|
|
/* Get current sample position in world coordinates */
|
|
|
|
copy_v3_v3(ray_start, bData->realCoord[bData->s_pos[index] + ss].v);
|
|
|
|
copy_v3_v3(ray_dir, bData->bNormal[index].invNorm);
|
|
|
|
|
|
|
|
/* a simple hack to minimize chance of ray leaks at identical ray <-> edge locations */
|
|
|
|
add_v3_fl(ray_start, 0.001f);
|
|
|
|
|
|
|
|
hit.index = -1;
|
|
|
|
hit.dist = 9999;
|
|
|
|
nearest.index = -1;
|
|
|
|
nearest.dist = brush_radius * brush_radius; /* find_nearest 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;
|
|
|
|
|
2012-06-25 07:24:48 +00:00
|
|
|
if (quad) { v2 = mface[hit.index].v3; v3 = mface[hit.index].v4; }
|
2012-05-12 16:11:34 +00:00
|
|
|
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 face normal are facing same direction
|
|
|
|
* hit point is inside a closed mesh. */
|
|
|
|
if (dot >= 0) {
|
|
|
|
float dist = hit.dist;
|
|
|
|
int f_index = hit.index;
|
|
|
|
|
|
|
|
/* Also cast a ray in opposite direction to make sure
|
2012-05-16 23:37:23 +00:00
|
|
|
* point is at least surrounded by two brush faces */
|
2012-05-12 16:11:34 +00:00
|
|
|
negate_v3(ray_dir);
|
|
|
|
hit.index = -1;
|
|
|
|
hit.dist = 9999;
|
|
|
|
|
|
|
|
BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_dir, 0.0f, &hit, mesh_faces_spherecast_dp, &treeData);
|
|
|
|
|
|
|
|
if (hit.index != -1) {
|
|
|
|
/* Add factor on supersample filter */
|
|
|
|
volume_factor = 1.0f;
|
|
|
|
hit_found = HIT_VOLUME;
|
|
|
|
|
|
|
|
/* Mark hit info */
|
|
|
|
madd_v3_v3v3fl(hitCoord, ray_start, ray_dir, hit.dist); /* Calculate final hit coordinates */
|
|
|
|
depth += dist * sample_factor;
|
|
|
|
hitFace = f_index;
|
|
|
|
hitQuad = quad;
|
|
|
|
}
|
|
|
|
}
|
2011-07-22 18:37:30 +00:00
|
|
|
}
|
2011-09-10 08:55:44 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
/* Check proximity collision */
|
|
|
|
if ((brush->collision == MOD_DPAINT_COL_DIST || brush->collision == MOD_DPAINT_COL_VOLDIST) &&
|
|
|
|
(!hit_found || (brush->flags & MOD_DPAINT_INVERSE_PROX)))
|
|
|
|
{
|
|
|
|
float proxDist = -1.0f;
|
2012-12-02 16:01:06 +00:00
|
|
|
float hitCo[3] = {0.0f, 0.0f, 0.0f};
|
2012-05-12 16:11:34 +00:00
|
|
|
short hQuad;
|
|
|
|
int face;
|
|
|
|
|
|
|
|
/* if inverse prox and no hit found, skip this sample */
|
|
|
|
if (inner_proximity && !hit_found) continue;
|
|
|
|
|
|
|
|
/* If pure distance proximity, find the nearest point on the mesh */
|
|
|
|
if (!(brush->flags & MOD_DPAINT_PROX_PROJECT)) {
|
|
|
|
if (BLI_bvhtree_find_nearest(treeData.tree, ray_start, &nearest, mesh_faces_nearest_point_dp, &treeData) != -1) {
|
|
|
|
proxDist = sqrtf(nearest.dist);
|
|
|
|
copy_v3_v3(hitCo, nearest.co);
|
|
|
|
hQuad = (nearest.no[0] == 1.0f);
|
|
|
|
face = nearest.index;
|
|
|
|
}
|
2011-09-10 08:55:44 +00:00
|
|
|
}
|
2012-05-12 16:11:34 +00:00
|
|
|
else { /* else cast a ray in defined projection direction */
|
|
|
|
float proj_ray[3] = {0.0f};
|
|
|
|
|
|
|
|
if (brush->ray_dir == MOD_DPAINT_RAY_CANVAS) {
|
|
|
|
copy_v3_v3(proj_ray, bData->bNormal[index].invNorm);
|
|
|
|
negate_v3(proj_ray);
|
|
|
|
}
|
|
|
|
else if (brush->ray_dir == MOD_DPAINT_RAY_BRUSH_AVG) {
|
|
|
|
copy_v3_v3(proj_ray, avg_brushNor);
|
|
|
|
}
|
|
|
|
else { /* MOD_DPAINT_RAY_ZPLUS */
|
|
|
|
proj_ray[2] = 1.0f;
|
|
|
|
}
|
|
|
|
hit.index = -1;
|
|
|
|
hit.dist = brush_radius;
|
|
|
|
|
|
|
|
/* Do a face normal directional raycast, and use that distance */
|
|
|
|
if (BLI_bvhtree_ray_cast(treeData.tree, ray_start, proj_ray, 0.0f, &hit, mesh_faces_spherecast_dp, &treeData) != -1) {
|
|
|
|
proxDist = hit.dist;
|
|
|
|
madd_v3_v3v3fl(hitCo, ray_start, proj_ray, hit.dist); /* Calculate final hit coordinates */
|
|
|
|
hQuad = (hit.no[0] == 1.0f);
|
|
|
|
face = hit.index;
|
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
/* If a hit was found, calculate required values */
|
|
|
|
if (proxDist >= 0.0f && proxDist <= brush_radius) {
|
|
|
|
proximity_factor = proxDist / brush_radius;
|
|
|
|
CLAMP(proximity_factor, 0.0f, 1.0f);
|
|
|
|
if (!inner_proximity)
|
|
|
|
proximity_factor = 1.0f - proximity_factor;
|
2011-06-17 18:04:56 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
hit_found = HIT_PROXIMITY;
|
2011-07-10 16:08:26 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
/* if no volume hit, use prox point face info */
|
|
|
|
if (hitFace == -1) {
|
|
|
|
copy_v3_v3(hitCoord, hitCo);
|
|
|
|
hitQuad = hQuad;
|
|
|
|
hitFace = face;
|
|
|
|
}
|
2011-06-17 18:04:56 +00:00
|
|
|
}
|
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
/* mix final sample strength depending on brush settings */
|
|
|
|
if (hit_found) {
|
|
|
|
/* if "negate volume" enabled, negate all factors within volume*/
|
|
|
|
if (brush->collision == MOD_DPAINT_COL_VOLDIST && brush->flags & MOD_DPAINT_NEGATE_VOLUME) {
|
|
|
|
volume_factor = 1.0f - volume_factor;
|
|
|
|
if (inner_proximity)
|
|
|
|
proximity_factor = 1.0f - proximity_factor;
|
|
|
|
}
|
2011-11-11 10:46:26 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
/* apply final sample depending on final hit type */
|
|
|
|
if (hit_found == HIT_VOLUME) {
|
|
|
|
sampleStrength = volume_factor;
|
|
|
|
}
|
|
|
|
else if (hit_found == HIT_PROXIMITY) {
|
|
|
|
/* apply falloff curve to the proximity_factor */
|
|
|
|
if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP && do_colorband(brush->paint_ramp, (1.0f - proximity_factor), prox_colorband))
|
|
|
|
proximity_factor = prox_colorband[3];
|
|
|
|
else if (brush->proximity_falloff == MOD_DPAINT_PRFALL_CONSTANT)
|
|
|
|
proximity_factor = (!inner_proximity || brush->flags & MOD_DPAINT_NEGATE_VOLUME) ? 1.0f : 0.0f;
|
|
|
|
/* apply sample */
|
|
|
|
sampleStrength = proximity_factor;
|
|
|
|
}
|
2011-11-11 10:46:26 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
sampleStrength *= sample_factor;
|
2011-08-03 18:31:48 +00:00
|
|
|
}
|
2012-07-07 22:51:57 +00:00
|
|
|
else {
|
|
|
|
continue;
|
|
|
|
}
|
2012-05-12 16:11:34 +00:00
|
|
|
|
|
|
|
/* velocity brush, only do on main sample */
|
|
|
|
if (brush->flags & MOD_DPAINT_USES_VELOCITY && ss == 0 && brushVelocity) {
|
|
|
|
int v1, v2, v3;
|
|
|
|
float weights[4];
|
|
|
|
float brushPointVelocity[3];
|
|
|
|
float velocity[3];
|
|
|
|
|
|
|
|
if (!hitQuad) {
|
|
|
|
v1 = mface[hitFace].v1;
|
|
|
|
v2 = mface[hitFace].v2;
|
|
|
|
v3 = mface[hitFace].v3;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
v1 = mface[hitFace].v2;
|
|
|
|
v2 = mface[hitFace].v3;
|
|
|
|
v3 = mface[hitFace].v4;
|
|
|
|
}
|
|
|
|
/* calculate barycentric weights for hit point */
|
|
|
|
interp_weights_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, hitCoord);
|
2011-06-16 10:41:00 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
/* simple check based on brush surface velocity,
|
|
|
|
* todo: perhaps implement something that handles volume movement as well */
|
2011-07-22 18:37:30 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
/* interpolate vertex speed vectors to get hit point velocity */
|
|
|
|
interp_v3_v3v3v3(brushPointVelocity,
|
|
|
|
brushVelocity[v1].v,
|
|
|
|
brushVelocity[v2].v,
|
|
|
|
brushVelocity[v3].v, weights);
|
|
|
|
|
|
|
|
/* substract canvas point velocity */
|
|
|
|
if (bData->velocity) {
|
|
|
|
sub_v3_v3v3(velocity, brushPointVelocity, bData->velocity[index].v);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
copy_v3_v3(velocity, brushPointVelocity);
|
|
|
|
}
|
|
|
|
velocity_val = len_v3(velocity);
|
|
|
|
|
|
|
|
/* if brush has smudge enabled store brush velocity */
|
|
|
|
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT &&
|
|
|
|
brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity)
|
|
|
|
{
|
|
|
|
copy_v3_v3(&bData->brush_velocity[index * 4], velocity);
|
|
|
|
mul_v3_fl(&bData->brush_velocity[index * 4], 1.0f / velocity_val);
|
|
|
|
bData->brush_velocity[index * 4 + 3] = velocity_val;
|
|
|
|
}
|
2011-08-03 18:31:48 +00:00
|
|
|
}
|
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
/*
|
|
|
|
* Process hit color and alpha
|
|
|
|
*/
|
|
|
|
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
|
|
|
|
float sampleColor[3];
|
|
|
|
float alpha_factor = 1.0f;
|
|
|
|
|
|
|
|
sampleColor[0] = brush->r;
|
|
|
|
sampleColor[1] = brush->g;
|
|
|
|
sampleColor[2] = brush->b;
|
|
|
|
|
|
|
|
/* Get material+textures color on hit point if required */
|
|
|
|
if (brush_usesMaterial(brush, scene))
|
|
|
|
dynamicPaint_doMaterialTex(bMats, sampleColor, &alpha_factor, brushOb, bData->realCoord[bData->s_pos[index] + ss].v, hitCoord, hitFace, hitQuad, brush->dm);
|
|
|
|
|
|
|
|
/* Sample proximity colorband if required */
|
|
|
|
if ((hit_found == HIT_PROXIMITY) && (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP)) {
|
|
|
|
if (!(brush->flags & MOD_DPAINT_RAMP_ALPHA)) {
|
|
|
|
sampleColor[0] = prox_colorband[0];
|
|
|
|
sampleColor[1] = prox_colorband[1];
|
|
|
|
sampleColor[2] = prox_colorband[2];
|
|
|
|
}
|
2011-08-03 18:31:48 +00:00
|
|
|
}
|
2012-05-12 16:11:34 +00:00
|
|
|
|
|
|
|
/* Add AA sample */
|
|
|
|
paintColor[0] += sampleColor[0];
|
|
|
|
paintColor[1] += sampleColor[1];
|
|
|
|
paintColor[2] += sampleColor[2];
|
|
|
|
sampleStrength *= alpha_factor;
|
|
|
|
numOfHits++;
|
2011-07-22 18:37:30 +00:00
|
|
|
}
|
2011-07-10 16:08:26 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
/* apply sample strength */
|
|
|
|
brushStrength += sampleStrength;
|
|
|
|
} // end supersampling
|
2011-05-24 07:08:58 +00:00
|
|
|
|
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
/* if any sample was inside paint range */
|
|
|
|
if (brushStrength > 0.0f || depth > 0.0f) {
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
/* apply supersampling results */
|
|
|
|
if (samples > 1) {
|
|
|
|
brushStrength /= total_sample;
|
|
|
|
}
|
|
|
|
CLAMP(brushStrength, 0.0f, 1.0f);
|
2011-08-03 18:31:48 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
|
|
|
|
/* Get final pixel color and alpha */
|
|
|
|
paintColor[0] /= numOfHits;
|
|
|
|
paintColor[1] /= numOfHits;
|
|
|
|
paintColor[2] /= numOfHits;
|
|
|
|
}
|
|
|
|
/* get final object space depth */
|
|
|
|
else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
|
2012-05-20 19:49:27 +00:00
|
|
|
surface->type == MOD_DPAINT_SURFACE_T_WAVE)
|
|
|
|
{
|
2012-05-12 16:11:34 +00:00
|
|
|
depth /= bData->bNormal[index].normal_scale * total_sample;
|
|
|
|
}
|
2011-08-03 18:31:48 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
dynamicPaint_updatePointData(surface, index, brush, paintColor, brushStrength, depth, velocity_val, timescale);
|
2011-08-03 18:31:48 +00:00
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-09-05 16:04:15 +00:00
|
|
|
/* free bvh tree */
|
2011-05-24 07:08:58 +00:00
|
|
|
free_bvhtree_from_mesh(&treeData);
|
|
|
|
dm->release(dm);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
/* free brush velocity data */
|
|
|
|
if (brushVelocity)
|
|
|
|
MEM_freeN(brushVelocity);
|
|
|
|
|
2011-05-24 07:08:58 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* Paint a particle system to the surface
|
|
|
|
*/
|
2011-11-10 12:28:26 +00:00
|
|
|
static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
|
|
|
|
ParticleSystem *psys,
|
|
|
|
DynamicPaintBrushSettings *brush,
|
2011-11-10 13:00:27 +00:00
|
|
|
float timescale)
|
2011-05-24 07:08:58 +00:00
|
|
|
{
|
2012-05-12 16:11:34 +00:00
|
|
|
ParticleSettings *part = psys->part;
|
2011-05-24 07:08:58 +00:00
|
|
|
ParticleData *pa = NULL;
|
2011-06-16 10:41:00 +00:00
|
|
|
PaintSurfaceData *sData = surface->data;
|
2011-07-22 18:37:30 +00:00
|
|
|
PaintBakeData *bData = sData->bData;
|
|
|
|
VolumeGrid *grid = bData->grid;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
|
|
|
KDTree *tree;
|
|
|
|
int particlesAdded = 0;
|
|
|
|
int invalidParticles = 0;
|
|
|
|
int p = 0;
|
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
float solidradius = surface->radius_scale * ((brush->flags & MOD_DPAINT_PART_RAD) ? psys->part->size : brush->particle_radius);
|
|
|
|
float smooth = brush->particle_smooth * surface->radius_scale;
|
2011-07-22 18:37:30 +00:00
|
|
|
|
|
|
|
float range = solidradius + smooth;
|
2011-08-03 18:31:48 +00:00
|
|
|
float particle_timestep = 0.04f * part->timetweak;
|
2011-07-22 18:37:30 +00:00
|
|
|
|
2011-11-11 10:46:26 +00:00
|
|
|
Bounds3D part_bb = {0};
|
2011-07-22 18:37:30 +00:00
|
|
|
|
2011-05-24 07:08:58 +00:00
|
|
|
if (psys->totpart < 1) return 1;
|
|
|
|
|
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* Build a kd-tree to optimize distance search
|
|
|
|
*/
|
|
|
|
tree = BLI_kdtree_new(psys->totpart);
|
2011-05-24 07:08:58 +00:00
|
|
|
|
|
|
|
/* loop through particles and insert valid ones to the tree */
|
2012-05-19 13:55:54 +00:00
|
|
|
for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++) {
|
2011-05-24 07:08:58 +00:00
|
|
|
|
|
|
|
/* Proceed only if particle is active */
|
2012-05-12 16:11:34 +00:00
|
|
|
if (pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN) == 0) continue;
|
|
|
|
else if (pa->alive == PARS_DEAD && (part->flag & PART_DIED) == 0) continue;
|
2012-03-24 06:18:31 +00:00
|
|
|
else if (pa->flag & PARS_UNEXIST) continue;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
|
|
|
/* for debug purposes check if any NAN particle proceeds
|
2012-05-12 16:11:34 +00:00
|
|
|
* For some reason they get past activity check, this should rule most of them out */
|
2012-06-25 07:24:48 +00:00
|
|
|
if (isnan(pa->state.co[0]) || isnan(pa->state.co[1]) || isnan(pa->state.co[2])) { invalidParticles++; continue; }
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
/* make sure particle is close enough to canvas */
|
|
|
|
if (!boundIntersectPoint(&grid->grid_bounds, pa->state.co, range)) continue;
|
|
|
|
|
2011-05-24 07:08:58 +00:00
|
|
|
BLI_kdtree_insert(tree, p, pa->state.co, NULL);
|
2011-07-22 18:37:30 +00:00
|
|
|
|
|
|
|
/* calc particle system bounds */
|
2011-09-05 16:04:15 +00:00
|
|
|
boundInsert(&part_bb, pa->state.co);
|
2011-07-22 18:37:30 +00:00
|
|
|
|
2011-05-24 07:08:58 +00:00
|
|
|
particlesAdded++;
|
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
if (invalidParticles)
|
2011-05-24 07:08:58 +00:00
|
|
|
printf("Warning: Invalid particle(s) found!\n");
|
|
|
|
|
|
|
|
/* If no suitable particles were found, exit */
|
|
|
|
if (particlesAdded < 1) {
|
|
|
|
BLI_kdtree_free(tree);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-10-22 16:16:14 +00:00
|
|
|
/* begin thread safe malloc */
|
|
|
|
BLI_begin_threaded_malloc();
|
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
/* only continue if particle bb is close enough to canvas bb */
|
2012-04-28 06:31:57 +00:00
|
|
|
if (boundsIntersectDist(&grid->grid_bounds, &part_bb, range)) {
|
2011-07-22 18:37:30 +00:00
|
|
|
int c_index;
|
2012-05-12 16:11:34 +00:00
|
|
|
int total_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
|
2011-07-22 18:37:30 +00:00
|
|
|
|
|
|
|
/* balance tree */
|
|
|
|
BLI_kdtree_balance(tree);
|
|
|
|
|
|
|
|
/* loop through space partitioning grid */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (c_index = 0; c_index < total_cells; c_index++) {
|
2011-07-22 18:37:30 +00:00
|
|
|
int id;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
/* check cell bounding box */
|
|
|
|
if (!grid->s_num[c_index] ||
|
2012-04-28 06:31:57 +00:00
|
|
|
!boundsIntersectDist(&grid->bounds[c_index], &part_bb, range))
|
|
|
|
{
|
2011-07-22 18:37:30 +00:00
|
|
|
continue;
|
2012-04-28 06:31:57 +00:00
|
|
|
}
|
2011-07-22 18:37:30 +00:00
|
|
|
|
|
|
|
/* loop through cell points */
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-04-28 06:31:57 +00:00
|
|
|
for (id = 0; id < grid->s_num[c_index]; id++) {
|
2011-07-22 18:37:30 +00:00
|
|
|
int index = grid->t_index[grid->s_pos[c_index] + id];
|
|
|
|
float disp_intersect = 0.0f;
|
|
|
|
float radius = 0.0f;
|
|
|
|
float strength = 0.0f;
|
2011-08-03 18:31:48 +00:00
|
|
|
float velocity_val = 0.0f;
|
2012-05-12 16:11:34 +00:00
|
|
|
int part_index = -1;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* With predefined radius, there is no variation between particles.
|
|
|
|
* It's enough to just find the nearest one.
|
|
|
|
*/
|
2011-07-22 18:37:30 +00:00
|
|
|
{
|
|
|
|
KDTreeNearest nearest;
|
2011-08-28 16:36:47 +00:00
|
|
|
float smooth_range, part_solidradius;
|
2011-07-22 18:37:30 +00:00
|
|
|
|
|
|
|
/* Find nearest particle and get distance to it */
|
|
|
|
BLI_kdtree_find_nearest(tree, bData->realCoord[bData->s_pos[index]].v, NULL, &nearest);
|
2011-09-05 16:04:15 +00:00
|
|
|
/* if outside maximum range, no other particle can influence either */
|
|
|
|
if (nearest.dist > range) continue;
|
|
|
|
|
2011-08-28 16:36:47 +00:00
|
|
|
if (brush->flags & MOD_DPAINT_PART_RAD) {
|
|
|
|
/* use particles individual size */
|
|
|
|
ParticleData *pa = psys->particles + nearest.index;
|
|
|
|
part_solidradius = pa->size;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
part_solidradius = solidradius;
|
|
|
|
}
|
|
|
|
radius = part_solidradius + smooth;
|
|
|
|
if (nearest.dist < radius) {
|
|
|
|
/* distances inside solid radius has maximum influence -> dist = 0 */
|
|
|
|
smooth_range = (nearest.dist - part_solidradius);
|
2012-05-12 16:11:34 +00:00
|
|
|
if (smooth_range < 0.0f) smooth_range = 0.0f;
|
2011-08-28 16:36:47 +00:00
|
|
|
/* do smoothness if enabled */
|
2012-05-12 16:11:34 +00:00
|
|
|
if (smooth) smooth_range /= smooth;
|
2011-07-22 18:37:30 +00:00
|
|
|
|
2011-08-28 16:36:47 +00:00
|
|
|
strength = 1.0f - smooth_range;
|
|
|
|
disp_intersect = radius - nearest.dist;
|
|
|
|
part_index = nearest.index;
|
|
|
|
}
|
2011-07-22 18:37:30 +00:00
|
|
|
}
|
|
|
|
/* If using random per particle radius and closest particle didn't give max influence */
|
|
|
|
if (brush->flags & MOD_DPAINT_PART_RAD && strength < 1.0f && psys->part->randsize > 0.0f) {
|
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* If we use per particle radius, we have to sample all particles
|
|
|
|
* within max radius range
|
|
|
|
*/
|
2011-10-22 16:16:14 +00:00
|
|
|
KDTreeNearest *nearest;
|
|
|
|
|
2013-09-01 20:17:56 +00:00
|
|
|
int n, particles;
|
2012-05-12 16:11:34 +00:00
|
|
|
float smooth_range = smooth * (1.0f - strength), dist;
|
2011-07-22 18:37:30 +00:00
|
|
|
/* calculate max range that can have particles with higher influence than the nearest one */
|
2012-05-12 16:11:34 +00:00
|
|
|
float max_range = smooth - strength * smooth + solidradius;
|
2012-12-02 16:01:06 +00:00
|
|
|
/* Make gcc happy! */
|
|
|
|
dist = max_range;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2013-09-01 20:17:56 +00:00
|
|
|
particles = BLI_kdtree_range_search(tree, bData->realCoord[bData->s_pos[index]].v, NULL,
|
|
|
|
&nearest, max_range);
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
/* Find particle that produces highest influence */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (n = 0; n < particles; n++) {
|
2011-07-22 18:37:30 +00:00
|
|
|
ParticleData *pa = psys->particles + nearest[n].index;
|
|
|
|
float s_range;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
/* skip if out of range */
|
|
|
|
if (nearest[n].dist > (pa->size + smooth))
|
|
|
|
continue;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
/* update hit data */
|
|
|
|
s_range = nearest[n].dist - pa->size;
|
2011-08-28 16:36:47 +00:00
|
|
|
/* skip if higher influence is already found */
|
2011-07-22 18:37:30 +00:00
|
|
|
if (smooth_range < s_range)
|
|
|
|
continue;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
/* update hit data */
|
|
|
|
smooth_range = s_range;
|
|
|
|
dist = nearest[n].dist;
|
2011-08-03 18:31:48 +00:00
|
|
|
part_index = nearest[n].index;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
/* If inside solid range and no disp depth required, no need to seek further */
|
2011-12-01 18:49:42 +00:00
|
|
|
if ( (s_range < 0.0f) &&
|
|
|
|
(surface->type != MOD_DPAINT_SURFACE_T_DISPLACE) &&
|
|
|
|
(surface->type != MOD_DPAINT_SURFACE_T_WAVE))
|
|
|
|
{
|
2011-09-05 16:04:15 +00:00
|
|
|
break;
|
2011-12-01 18:49:42 +00:00
|
|
|
}
|
2011-07-22 18:37:30 +00:00
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-10-22 16:16:14 +00:00
|
|
|
if (nearest) MEM_freeN(nearest);
|
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
/* now calculate influence for this particle */
|
2011-08-28 16:36:47 +00:00
|
|
|
{
|
2011-07-22 18:37:30 +00:00
|
|
|
float rad = radius + smooth, str;
|
2012-05-12 16:11:34 +00:00
|
|
|
if ((rad - dist) > disp_intersect) {
|
2011-08-03 18:31:48 +00:00
|
|
|
disp_intersect = radius - dist;
|
2011-07-22 18:37:30 +00:00
|
|
|
radius = rad;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* do smoothness if enabled */
|
2012-05-12 16:11:34 +00:00
|
|
|
if (smooth_range < 0.0f) smooth_range = 0.0f;
|
|
|
|
if (smooth) smooth_range /= smooth;
|
2011-07-22 18:37:30 +00:00
|
|
|
str = 1.0f - smooth_range;
|
|
|
|
/* if influence is greater, use this one */
|
|
|
|
if (str > strength) strength = str;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
if (strength > 0.001f) {
|
2011-07-22 18:37:30 +00:00
|
|
|
float paintColor[4] = {0.0f};
|
|
|
|
float depth = 0.0f;
|
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
/* apply velocity */
|
2011-12-01 18:49:42 +00:00
|
|
|
if ((brush->flags & MOD_DPAINT_USES_VELOCITY) && (part_index != -1)) {
|
2011-08-03 18:31:48 +00:00
|
|
|
float velocity[3];
|
|
|
|
ParticleData *pa = psys->particles + part_index;
|
|
|
|
mul_v3_v3fl(velocity, pa->state.vel, particle_timestep);
|
2011-08-04 07:09:21 +00:00
|
|
|
|
|
|
|
/* substract canvas point velocity */
|
2011-08-05 09:31:35 +00:00
|
|
|
if (bData->velocity) {
|
2011-10-28 14:46:09 +00:00
|
|
|
sub_v3_v3(velocity, bData->velocity[index].v);
|
2011-08-05 09:31:35 +00:00
|
|
|
}
|
2011-08-03 18:31:48 +00:00
|
|
|
velocity_val = len_v3(velocity);
|
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* store brush velocity for smudge */
|
2011-12-01 18:49:42 +00:00
|
|
|
if ( (surface->type == MOD_DPAINT_SURFACE_T_PAINT) &&
|
|
|
|
(brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity))
|
|
|
|
{
|
2012-05-12 16:11:34 +00:00
|
|
|
copy_v3_v3(&bData->brush_velocity[index * 4], velocity);
|
|
|
|
mul_v3_fl(&bData->brush_velocity[index * 4], 1.0f / velocity_val);
|
|
|
|
bData->brush_velocity[index * 4 + 3] = velocity_val;
|
2011-08-03 18:31:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
|
2011-12-01 18:49:42 +00:00
|
|
|
copy_v3_v3(paintColor, &brush->r);
|
2011-07-22 18:37:30 +00:00
|
|
|
}
|
2011-12-01 18:49:42 +00:00
|
|
|
else if ( (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) ||
|
|
|
|
(surface->type == MOD_DPAINT_SURFACE_T_WAVE))
|
|
|
|
{
|
2012-05-12 16:11:34 +00:00
|
|
|
/* get displace depth */
|
2011-11-11 12:00:08 +00:00
|
|
|
disp_intersect = (1.0f - sqrtf(disp_intersect / radius)) * radius;
|
2011-07-22 18:37:30 +00:00
|
|
|
depth = (radius - disp_intersect) / bData->bNormal[index].normal_scale;
|
2012-05-12 16:11:34 +00:00
|
|
|
if (depth < 0.0f) depth = 0.0f;
|
2011-07-22 18:37:30 +00:00
|
|
|
}
|
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
dynamicPaint_updatePointData(surface, index, brush, paintColor, strength, depth, velocity_val, timescale);
|
2011-07-22 18:37:30 +00:00
|
|
|
}
|
2011-07-08 11:03:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-10-22 16:16:14 +00:00
|
|
|
BLI_end_threaded_malloc();
|
2011-07-08 11:03:37 +00:00
|
|
|
BLI_kdtree_free(tree);
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-07-08 11:03:37 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* paint a single point of defined proximity radius to the surface */
|
2011-08-03 18:31:48 +00:00
|
|
|
static int dynamicPaint_paintSinglePoint(DynamicPaintSurface *surface, float *pointCoord, DynamicPaintBrushSettings *brush,
|
2011-11-10 13:00:27 +00:00
|
|
|
Object *brushOb, BrushMaterials *bMats, Scene *scene, float timescale)
|
2011-07-08 11:03:37 +00:00
|
|
|
{
|
2011-07-08 12:05:34 +00:00
|
|
|
int index;
|
2012-01-16 17:18:07 +00:00
|
|
|
float brush_radius = brush->paint_distance * surface->radius_scale;
|
2011-07-08 11:03:37 +00:00
|
|
|
PaintSurfaceData *sData = surface->data;
|
2011-07-22 18:37:30 +00:00
|
|
|
PaintBakeData *bData = sData->bData;
|
2011-08-03 18:31:48 +00:00
|
|
|
Vec3f brushVel;
|
|
|
|
|
2011-08-04 07:09:21 +00:00
|
|
|
if (brush->flags & MOD_DPAINT_USES_VELOCITY)
|
2011-11-10 13:00:27 +00:00
|
|
|
dynamicPaint_brushObjectCalculateVelocity(scene, brushOb, &brushVel, timescale);
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-07-08 11:03:37 +00:00
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* Loop through every surface point
|
|
|
|
*/
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-04-28 06:31:57 +00:00
|
|
|
for (index = 0; index < sData->total_points; index++) {
|
2011-07-22 18:37:30 +00:00
|
|
|
float distance = len_v3v3(pointCoord, bData->realCoord[bData->s_pos[index]].v);
|
2011-07-10 16:08:26 +00:00
|
|
|
float colorband[4] = {0.0f};
|
2011-07-08 11:03:37 +00:00
|
|
|
float strength;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-01-16 17:18:07 +00:00
|
|
|
if (distance > brush_radius) continue;
|
2011-07-10 16:08:26 +00:00
|
|
|
|
2011-07-08 11:03:37 +00:00
|
|
|
/* Smooth range or color ramp */
|
|
|
|
if (brush->proximity_falloff == MOD_DPAINT_PRFALL_SMOOTH ||
|
2012-05-20 19:49:27 +00:00
|
|
|
brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP)
|
|
|
|
{
|
2012-01-16 17:18:07 +00:00
|
|
|
strength = 1.0f - distance / brush_radius;
|
2011-07-10 16:08:26 +00:00
|
|
|
CLAMP(strength, 0.0f, 1.0f);
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
2013-03-09 03:46:30 +00:00
|
|
|
else {
|
|
|
|
strength = 1.0f;
|
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-07-08 11:03:37 +00:00
|
|
|
if (strength >= 0.001f) {
|
2011-07-10 16:08:26 +00:00
|
|
|
float paintColor[3] = {0.0f};
|
2011-07-08 11:03:37 +00:00
|
|
|
float depth = 0.0f;
|
2011-08-04 07:09:21 +00:00
|
|
|
float velocity_val = 0.0f;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
/* material */
|
2011-11-09 15:46:53 +00:00
|
|
|
if (brush_usesMaterial(brush, scene)) {
|
2011-08-03 18:31:48 +00:00
|
|
|
float alpha_factor = 1.0f;
|
|
|
|
float hit_coord[3];
|
|
|
|
MVert *mvert = brush->dm->getVertArray(brush->dm);
|
2011-09-05 16:04:15 +00:00
|
|
|
/* use dummy coord of first vertex */
|
2011-10-28 14:46:09 +00:00
|
|
|
copy_v3_v3(hit_coord, mvert[0].co);
|
2011-09-05 16:04:15 +00:00
|
|
|
mul_m4_v3(brushOb->obmat, hit_coord);
|
2011-08-03 18:31:48 +00:00
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
dynamicPaint_doMaterialTex(bMats, paintColor, &alpha_factor, brushOb, bData->realCoord[bData->s_pos[index]].v, hit_coord, 0, 0, brush->dm);
|
2011-08-03 18:31:48 +00:00
|
|
|
}
|
|
|
|
|
2011-07-10 16:08:26 +00:00
|
|
|
/* color ramp */
|
2012-05-12 16:11:34 +00:00
|
|
|
if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP && do_colorband(brush->paint_ramp, (1.0f - strength), colorband))
|
2011-07-10 16:08:26 +00:00
|
|
|
strength = colorband[3];
|
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
if (brush->flags & MOD_DPAINT_USES_VELOCITY) {
|
2011-08-04 07:09:21 +00:00
|
|
|
float velocity[3];
|
|
|
|
|
|
|
|
/* substract canvas point velocity */
|
2011-08-05 09:31:35 +00:00
|
|
|
if (bData->velocity) {
|
2011-10-28 14:46:09 +00:00
|
|
|
sub_v3_v3v3(velocity, brushVel.v, bData->velocity[index].v);
|
2011-08-05 09:31:35 +00:00
|
|
|
}
|
|
|
|
else {
|
2011-10-28 14:46:09 +00:00
|
|
|
copy_v3_v3(velocity, brushVel.v);
|
2011-08-05 09:31:35 +00:00
|
|
|
}
|
2011-08-04 07:09:21 +00:00
|
|
|
velocity_val = len_v3(velocity);
|
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* store brush velocity for smudge */
|
2011-11-20 10:52:25 +00:00
|
|
|
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT &&
|
2012-05-12 16:11:34 +00:00
|
|
|
brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity)
|
|
|
|
{
|
|
|
|
copy_v3_v3(&bData->brush_velocity[index * 4], velocity);
|
|
|
|
mul_v3_fl(&bData->brush_velocity[index * 4], 1.0f / velocity_val);
|
|
|
|
bData->brush_velocity[index * 4 + 3] = velocity_val;
|
2011-08-03 18:31:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-08 11:03:37 +00:00
|
|
|
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
|
2011-08-03 18:31:48 +00:00
|
|
|
if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
|
2012-05-20 19:49:27 +00:00
|
|
|
!(brush->flags & MOD_DPAINT_RAMP_ALPHA))
|
|
|
|
{
|
2011-07-10 16:08:26 +00:00
|
|
|
paintColor[0] = colorband[0];
|
|
|
|
paintColor[1] = colorband[1];
|
|
|
|
paintColor[2] = colorband[2];
|
|
|
|
}
|
|
|
|
else {
|
2011-11-09 15:46:53 +00:00
|
|
|
if (!brush_usesMaterial(brush, scene)) {
|
2011-08-03 18:31:48 +00:00
|
|
|
paintColor[0] = brush->r;
|
|
|
|
paintColor[1] = brush->g;
|
|
|
|
paintColor[2] = brush->b;
|
|
|
|
}
|
2011-07-10 16:08:26 +00:00
|
|
|
}
|
2011-06-18 18:41:20 +00:00
|
|
|
}
|
2011-07-08 11:03:37 +00:00
|
|
|
else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
|
2012-05-12 16:11:34 +00:00
|
|
|
surface->type == MOD_DPAINT_SURFACE_T_WAVE)
|
|
|
|
{
|
|
|
|
/* get displace depth */
|
|
|
|
float disp_intersect = (1.0f - sqrtf((brush_radius - distance) / brush_radius)) * brush_radius;
|
2012-01-16 17:18:07 +00:00
|
|
|
depth = (brush_radius - disp_intersect) / bData->bNormal[index].normal_scale;
|
2012-05-12 16:11:34 +00:00
|
|
|
if (depth < 0.0f) depth = 0.0f;
|
2011-06-18 18:41:20 +00:00
|
|
|
}
|
2011-08-03 18:31:48 +00:00
|
|
|
dynamicPaint_updatePointData(surface, index, brush, paintColor, strength, depth, velocity_val, timescale);
|
2011-06-18 18:41:20 +00:00
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/***************************** Dynamic Paint Step / Baking ******************************/
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-07-02 18:06:39 +00:00
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* Calculate current frame distances and directions for adjacency data
|
|
|
|
*/
|
2012-01-24 17:28:50 +00:00
|
|
|
static void dynamicPaint_prepareAdjacencyData(DynamicPaintSurface *surface, int force_init)
|
2011-07-02 18:06:39 +00:00
|
|
|
{
|
|
|
|
PaintSurfaceData *sData = surface->data;
|
2011-07-22 18:37:30 +00:00
|
|
|
PaintBakeData *bData = sData->bData;
|
2012-01-24 17:28:50 +00:00
|
|
|
BakeAdjPoint *bNeighs;
|
2011-07-22 18:37:30 +00:00
|
|
|
PaintAdjData *adj_data = sData->adj_data;
|
|
|
|
Vec3f *realCoord = bData->realCoord;
|
2011-07-02 18:06:39 +00:00
|
|
|
int index;
|
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
if ((!surface_usesAdjDistance(surface) && !force_init) || !sData->adj_data) return;
|
2011-07-22 18:37:30 +00:00
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
if (bData->bNeighs) MEM_freeN(bData->bNeighs);
|
2012-05-12 16:11:34 +00:00
|
|
|
bNeighs = bData->bNeighs = MEM_mallocN(sData->adj_data->total_targets * sizeof(struct BakeAdjPoint), "PaintEffectBake");
|
2011-07-22 18:37:30 +00:00
|
|
|
if (!bNeighs) return;
|
|
|
|
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-04-28 06:31:57 +00:00
|
|
|
for (index = 0; index < sData->total_points; index++) {
|
2011-07-02 18:06:39 +00:00
|
|
|
int i;
|
2011-07-22 18:37:30 +00:00
|
|
|
int numOfNeighs = adj_data->n_num[index];
|
2011-07-02 18:06:39 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < numOfNeighs; i++) {
|
|
|
|
int n_index = adj_data->n_index[index] + i;
|
2011-07-22 18:37:30 +00:00
|
|
|
int t_index = adj_data->n_target[n_index];
|
2011-07-02 18:06:39 +00:00
|
|
|
|
|
|
|
/* dir vec */
|
2011-07-22 18:37:30 +00:00
|
|
|
sub_v3_v3v3(bNeighs[n_index].dir, realCoord[bData->s_pos[t_index]].v, realCoord[bData->s_pos[index]].v);
|
2011-07-02 18:06:39 +00:00
|
|
|
/* dist */
|
|
|
|
bNeighs[n_index].dist = len_v3(bNeighs[n_index].dir);
|
|
|
|
/* normalize dir */
|
2012-05-12 16:11:34 +00:00
|
|
|
if (bNeighs[n_index].dist) mul_v3_fl(bNeighs[n_index].dir, 1.0f / bNeighs[n_index].dist);
|
2011-07-02 18:06:39 +00:00
|
|
|
}
|
|
|
|
}
|
2011-08-03 18:31:48 +00:00
|
|
|
|
|
|
|
/* calculate average values (single thread) */
|
|
|
|
bData->average_dist = 0.0f;
|
2012-04-28 06:31:57 +00:00
|
|
|
for (index = 0; index < sData->total_points; index++) {
|
2011-08-03 18:31:48 +00:00
|
|
|
int i;
|
|
|
|
int numOfNeighs = adj_data->n_num[index];
|
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < numOfNeighs; i++) {
|
|
|
|
bData->average_dist += (double)bNeighs[adj_data->n_index[index] + i].dist;
|
2011-08-03 18:31:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
bData->average_dist /= adj_data->total_targets;
|
|
|
|
}
|
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* find two adjacency points (closest_id) and influence (closest_d) to move paint towards when affected by a force */
|
2012-09-15 01:52:28 +00:00
|
|
|
static void surface_determineForceTargetPoints(PaintSurfaceData *sData, int index, float force[3], float closest_d[2], int closest_id[2])
|
2011-09-05 16:04:15 +00:00
|
|
|
{
|
2012-01-24 17:28:50 +00:00
|
|
|
BakeAdjPoint *bNeighs = sData->bData->bNeighs;
|
2011-09-05 16:04:15 +00:00
|
|
|
int numOfNeighs = sData->adj_data->n_num[index];
|
|
|
|
int i;
|
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
closest_id[0] = closest_id[1] = -1;
|
|
|
|
closest_d[0] = closest_d[1] = -1.0f;
|
2011-09-05 16:04:15 +00:00
|
|
|
|
|
|
|
/* find closest neigh */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < numOfNeighs; i++) {
|
|
|
|
int n_index = sData->adj_data->n_index[index] + i;
|
2011-09-05 16:04:15 +00:00
|
|
|
float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
|
|
|
|
|
2012-06-25 07:24:48 +00:00
|
|
|
if (dir_dot > closest_d[0] && dir_dot > 0.0f) { closest_d[0] = dir_dot; closest_id[0] = n_index; }
|
2011-09-05 16:04:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (closest_d[0] < 0.0f) return;
|
|
|
|
|
|
|
|
/* find second closest neigh */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < numOfNeighs; i++) {
|
|
|
|
int n_index = sData->adj_data->n_index[index] + i;
|
2011-09-05 16:04:15 +00:00
|
|
|
float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
|
|
|
|
float closest_dot = dot_v3v3(bNeighs[n_index].dir, bNeighs[closest_id[0]].dir);
|
|
|
|
|
|
|
|
if (n_index == closest_id[0]) continue;
|
|
|
|
|
2012-03-01 12:20:18 +00:00
|
|
|
/* only accept neighbor at "other side" of the first one in relation to force dir
|
2012-05-12 16:11:34 +00:00
|
|
|
* so make sure angle between this and closest neigh is greater than first angle */
|
|
|
|
if (dir_dot > closest_d[1] && closest_dot < closest_d[0] && dir_dot > 0.0f) {
|
|
|
|
closest_d[1] = dir_dot; closest_id[1] = n_index;
|
|
|
|
}
|
2011-09-05 16:04:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* if two valid neighs found, calculate how force effect is divided
|
2012-05-12 16:11:34 +00:00
|
|
|
* evenly between them (so that d[0]+d[1] = 1.0)*/
|
2011-09-05 16:04:15 +00:00
|
|
|
if (closest_id[1] != -1) {
|
|
|
|
float force_proj[3];
|
|
|
|
float tangent[3];
|
2012-01-16 17:18:07 +00:00
|
|
|
float neigh_diff = acosf(dot_v3v3(bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir));
|
2011-09-05 16:04:15 +00:00
|
|
|
float force_intersect;
|
|
|
|
float temp;
|
|
|
|
|
2012-08-24 23:22:34 +00:00
|
|
|
/* project force vector on the plane determined by these two neighbor points
|
2012-05-12 16:11:34 +00:00
|
|
|
* and calculate relative force angle from it*/
|
2011-09-05 16:04:15 +00:00
|
|
|
cross_v3_v3v3(tangent, bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir);
|
|
|
|
normalize_v3(tangent);
|
|
|
|
force_intersect = dot_v3v3(force, tangent);
|
2012-05-12 16:11:34 +00:00
|
|
|
madd_v3_v3v3fl(force_proj, force, tangent, (-1.0f) * force_intersect);
|
2011-09-05 16:04:15 +00:00
|
|
|
normalize_v3(force_proj);
|
|
|
|
|
2012-03-09 00:41:09 +00:00
|
|
|
/* get drip factor based on force dir in relation to angle between those neighbors */
|
2011-09-05 16:04:15 +00:00
|
|
|
temp = dot_v3v3(bNeighs[closest_id[0]].dir, force_proj);
|
|
|
|
CLAMP(temp, -1.0f, 1.0f); /* float precision might cause values > 1.0f that return infinite */
|
2012-05-12 16:11:34 +00:00
|
|
|
closest_d[1] = acosf(temp) / neigh_diff;
|
2011-09-05 16:04:15 +00:00
|
|
|
closest_d[0] = 1.0f - closest_d[1];
|
|
|
|
|
|
|
|
/* and multiply depending on how deeply force intersects surface */
|
|
|
|
temp = fabs(force_intersect);
|
|
|
|
CLAMP(temp, 0.0f, 1.0f);
|
2012-05-12 16:42:12 +00:00
|
|
|
mul_v2_fl(closest_d, acosf(temp) / (float)M_PI_2);
|
2011-09-05 16:04:15 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-03-01 12:20:18 +00:00
|
|
|
/* if only single neighbor, still linearize force intersection effect */
|
2012-05-12 16:42:12 +00:00
|
|
|
closest_d[0] = 1.0f - acosf(closest_d[0]) / (float)M_PI_2;
|
2011-09-05 16:04:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-04 07:09:21 +00:00
|
|
|
static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrushSettings *brush, float timescale)
|
2011-08-03 18:31:48 +00:00
|
|
|
{
|
|
|
|
PaintSurfaceData *sData = surface->data;
|
|
|
|
PaintBakeData *bData = sData->bData;
|
2012-01-24 17:28:50 +00:00
|
|
|
BakeAdjPoint *bNeighs = sData->bData->bNeighs;
|
2011-08-03 18:31:48 +00:00
|
|
|
int index, steps, step;
|
|
|
|
float eff_scale, max_velocity = 0.0f;
|
|
|
|
|
|
|
|
if (!sData->adj_data) return;
|
|
|
|
|
|
|
|
/* find max velocity */
|
|
|
|
for (index = 0; index < sData->total_points; index++) {
|
2012-05-12 16:11:34 +00:00
|
|
|
float vel = bData->brush_velocity[index * 4 + 3];
|
2011-08-03 18:31:48 +00:00
|
|
|
if (vel > max_velocity) max_velocity = vel;
|
|
|
|
}
|
|
|
|
|
2011-08-04 07:09:21 +00:00
|
|
|
steps = (int)ceil(max_velocity / bData->average_dist * timescale);
|
2011-08-03 18:31:48 +00:00
|
|
|
CLAMP(steps, 0, 12);
|
2012-05-12 16:11:34 +00:00
|
|
|
eff_scale = brush->smudge_strength / (float)steps * timescale;
|
2011-08-03 18:31:48 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
for (step = 0; step < steps; step++) {
|
2011-08-03 18:31:48 +00:00
|
|
|
|
|
|
|
for (index = 0; index < sData->total_points; index++) {
|
|
|
|
int i;
|
2012-05-12 16:11:34 +00:00
|
|
|
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
|
|
|
|
float smudge_str = bData->brush_velocity[index * 4 + 3];
|
2011-08-03 18:31:48 +00:00
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* force targets */
|
|
|
|
int closest_id[2];
|
|
|
|
float closest_d[2];
|
2011-08-03 18:31:48 +00:00
|
|
|
|
|
|
|
if (!smudge_str) continue;
|
2011-09-05 16:04:15 +00:00
|
|
|
|
|
|
|
/* get force affect points */
|
2012-05-12 16:11:34 +00:00
|
|
|
surface_determineForceTargetPoints(sData, index, &bData->brush_velocity[index * 4], closest_d, closest_id);
|
2011-08-03 18:31:48 +00:00
|
|
|
|
|
|
|
/* Apply movement towards those two points */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < 2; i++) {
|
2011-08-03 18:31:48 +00:00
|
|
|
int n_index = closest_id[i];
|
2012-05-12 16:11:34 +00:00
|
|
|
if (n_index != -1 && closest_d[i] > 0.0f) {
|
2011-08-03 18:31:48 +00:00
|
|
|
float dir_dot = closest_d[i], dir_factor;
|
2012-05-12 16:11:34 +00:00
|
|
|
float speed_scale = eff_scale * smudge_str / bNeighs[n_index].dist;
|
|
|
|
PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[sData->adj_data->n_target[n_index]];
|
2011-08-03 18:31:48 +00:00
|
|
|
|
|
|
|
/* just skip if angle is too extreme */
|
|
|
|
if (dir_dot <= 0.0f) continue;
|
|
|
|
|
|
|
|
dir_factor = dir_dot * speed_scale;
|
|
|
|
if (dir_factor > brush->smudge_strength) dir_factor = brush->smudge_strength;
|
|
|
|
|
|
|
|
/* mix new color and alpha */
|
2012-01-16 17:18:07 +00:00
|
|
|
mixColors(ePoint->color, ePoint->alpha, pPoint->color, pPoint->alpha, dir_factor);
|
2012-05-12 16:11:34 +00:00
|
|
|
ePoint->alpha = ePoint->alpha * (1.0f - dir_factor) + pPoint->alpha * dir_factor;
|
2011-08-05 09:31:35 +00:00
|
|
|
|
2011-10-31 13:01:06 +00:00
|
|
|
/* smudge "wet layer" */
|
2012-01-16 17:18:07 +00:00
|
|
|
mixColors(ePoint->e_color, ePoint->e_alpha, pPoint->e_color, pPoint->e_alpha, dir_factor);
|
2012-05-12 16:11:34 +00:00
|
|
|
ePoint->e_alpha = ePoint->e_alpha * (1.0f - dir_factor) + pPoint->e_alpha * dir_factor;
|
|
|
|
pPoint->wetness *= (1.0f - dir_factor);
|
2011-08-03 18:31:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-07-02 18:06:39 +00:00
|
|
|
}
|
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
/*
|
2012-05-12 16:11:34 +00:00
|
|
|
* Prepare data required by effects for current frame.
|
|
|
|
* Returns number of steps required
|
|
|
|
*/
|
2011-07-22 18:37:30 +00:00
|
|
|
static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *scene, Object *ob, float **force, float timescale)
|
2011-06-27 07:30:58 +00:00
|
|
|
{
|
|
|
|
double average_force = 0.0f;
|
2012-05-12 16:11:34 +00:00
|
|
|
float shrink_speed = 0.0f, spread_speed = 0.0f;
|
2012-01-16 17:18:07 +00:00
|
|
|
float fastest_effect, avg_dist;
|
2011-06-27 07:30:58 +00:00
|
|
|
int steps;
|
|
|
|
PaintSurfaceData *sData = surface->data;
|
2011-07-22 18:37:30 +00:00
|
|
|
PaintBakeData *bData = sData->bData;
|
|
|
|
Vec3f *realCoord = bData->realCoord;
|
2011-06-27 07:30:58 +00:00
|
|
|
int index;
|
|
|
|
|
|
|
|
/* Init force data if required */
|
|
|
|
if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
|
|
|
|
float vel[3] = {0};
|
|
|
|
ListBase *effectors = pdInitEffectors(scene, ob, NULL, surface->effector_weights);
|
|
|
|
|
|
|
|
/* allocate memory for force data (dir vector + strength) */
|
2012-05-12 16:11:34 +00:00
|
|
|
*force = MEM_mallocN(sData->total_points * 4 * sizeof(float), "PaintEffectForces");
|
2011-06-27 07:30:58 +00:00
|
|
|
|
|
|
|
if (*force) {
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-04-28 06:31:57 +00:00
|
|
|
for (index = 0; index < sData->total_points; index++) {
|
2011-06-27 07:30:58 +00:00
|
|
|
float forc[3] = {0};
|
|
|
|
|
|
|
|
/* apply force fields */
|
|
|
|
if (effectors) {
|
|
|
|
EffectedPoint epoint;
|
2011-07-22 18:37:30 +00:00
|
|
|
pd_point_from_loc(scene, realCoord[bData->s_pos[index]].v, vel, index, &epoint);
|
2011-06-27 07:30:58 +00:00
|
|
|
epoint.vel_to_sec = 1.0f;
|
|
|
|
pdDoEffectors(effectors, NULL, surface->effector_weights, &epoint, forc, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if global gravity is enabled, add it too */
|
|
|
|
if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY)
|
|
|
|
/* also divide by 10 to about match default grav
|
2012-05-12 16:11:34 +00:00
|
|
|
* with default force strength (1.0) */
|
2011-06-27 07:30:58 +00:00
|
|
|
madd_v3_v3fl(forc, scene->physics_settings.gravity,
|
2012-05-12 16:11:34 +00:00
|
|
|
surface->effector_weights->global_gravity * surface->effector_weights->weight[0] / 10.f);
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
/* add surface point velocity and acceleration if enabled */
|
|
|
|
if (bData->velocity) {
|
|
|
|
if (surface->drip_vel)
|
2012-05-12 16:11:34 +00:00
|
|
|
madd_v3_v3fl(forc, bData->velocity[index].v, surface->drip_vel * (-1.0f));
|
2011-08-03 18:31:48 +00:00
|
|
|
|
|
|
|
/* acceleration */
|
|
|
|
if (bData->prev_velocity && surface->drip_acc) {
|
|
|
|
float acc[3];
|
2011-10-28 14:46:09 +00:00
|
|
|
copy_v3_v3(acc, bData->velocity[index].v);
|
2011-08-03 18:31:48 +00:00
|
|
|
sub_v3_v3(acc, bData->prev_velocity[index].v);
|
2012-05-12 16:11:34 +00:00
|
|
|
madd_v3_v3fl(forc, acc, surface->drip_acc * (-1.0f));
|
2011-08-03 18:31:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
/* force strength */
|
2012-05-12 16:11:34 +00:00
|
|
|
(*force)[index * 4 + 3] = len_v3(forc);
|
2011-06-27 07:30:58 +00:00
|
|
|
/* normalize and copy */
|
2012-05-12 16:11:34 +00:00
|
|
|
if ((*force)[index * 4 + 3]) mul_v3_fl(forc, 1.0f / (*force)[index * 4 + 3]);
|
|
|
|
copy_v3_v3(&((*force)[index * 4]), forc);
|
2011-06-27 07:30:58 +00:00
|
|
|
}
|
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
/* calculate average values (single thread) */
|
2012-04-28 06:31:57 +00:00
|
|
|
for (index = 0; index < sData->total_points; index++) {
|
2012-05-12 16:11:34 +00:00
|
|
|
average_force += (*force)[index * 4 + 3];
|
2011-08-03 18:31:48 +00:00
|
|
|
}
|
|
|
|
average_force /= sData->total_points;
|
2011-06-27 07:30:58 +00:00
|
|
|
}
|
2011-08-03 18:31:48 +00:00
|
|
|
pdEndEffectors(&effectors);
|
2011-06-27 07:30:58 +00:00
|
|
|
}
|
|
|
|
|
2012-09-26 20:05:38 +00:00
|
|
|
/* Get number of required steps using average point distance
|
2012-05-12 16:11:34 +00:00
|
|
|
* so that just a few ultra close pixels wont up substeps to max */
|
2011-06-27 07:30:58 +00:00
|
|
|
|
|
|
|
/* adjust number of required substep by fastest active effect */
|
|
|
|
if (surface->effect & MOD_DPAINT_EFFECT_DO_SPREAD)
|
|
|
|
spread_speed = surface->spread_speed;
|
|
|
|
if (surface->effect & MOD_DPAINT_EFFECT_DO_SHRINK)
|
|
|
|
shrink_speed = surface->shrink_speed;
|
|
|
|
|
2012-12-21 05:07:26 +00:00
|
|
|
fastest_effect = max_fff(spread_speed, shrink_speed, average_force);
|
2012-05-12 16:11:34 +00:00
|
|
|
avg_dist = bData->average_dist * CANVAS_REL_SIZE / getSurfaceDimension(sData);
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
steps = (int)ceil(1.5f * EFF_MOVEMENT_PER_FRAME * fastest_effect / avg_dist * timescale);
|
2012-01-16 17:18:07 +00:00
|
|
|
CLAMP(steps, 1, 20);
|
2011-06-27 07:30:58 +00:00
|
|
|
|
|
|
|
return steps;
|
|
|
|
}
|
|
|
|
|
2012-03-09 18:28:30 +00:00
|
|
|
/**
|
|
|
|
* Processes active effect step.
|
|
|
|
*/
|
2011-08-03 18:31:48 +00:00
|
|
|
static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, float *force, PaintPoint *prevPoint, float timescale, float steps)
|
2011-06-27 07:30:58 +00:00
|
|
|
{
|
|
|
|
PaintSurfaceData *sData = surface->data;
|
2012-01-24 17:28:50 +00:00
|
|
|
BakeAdjPoint *bNeighs = sData->bData->bNeighs;
|
2012-05-12 16:11:34 +00:00
|
|
|
float distance_scale = getSurfaceDimension(sData) / CANVAS_REL_SIZE;
|
2011-06-27 07:30:58 +00:00
|
|
|
int index;
|
2011-10-13 20:00:22 +00:00
|
|
|
timescale /= steps;
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2011-07-02 18:06:39 +00:00
|
|
|
if (!sData->adj_data) return;
|
2011-08-03 18:31:48 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
/*
|
2012-03-09 18:28:30 +00:00
|
|
|
* Spread Effect
|
|
|
|
*/
|
2012-02-27 10:35:39 +00:00
|
|
|
if (surface->effect & MOD_DPAINT_EFFECT_DO_SPREAD) {
|
2012-05-12 16:11:34 +00:00
|
|
|
float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->spread_speed * timescale;
|
2011-06-27 07:30:58 +00:00
|
|
|
|
|
|
|
/* Copy current surface to the previous points array to read unmodified values */
|
2012-05-12 16:11:34 +00:00
|
|
|
memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-04-28 06:31:57 +00:00
|
|
|
for (index = 0; index < sData->total_points; index++) {
|
2011-06-27 07:30:58 +00:00
|
|
|
int i;
|
2011-07-08 11:03:37 +00:00
|
|
|
int numOfNeighs = sData->adj_data->n_num[index];
|
2012-05-12 16:11:34 +00:00
|
|
|
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* Only reads values from the surface copy (prevPoint[]),
|
2012-03-09 18:28:30 +00:00
|
|
|
* so this one is thread safe */
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2012-03-01 12:20:18 +00:00
|
|
|
/* Loop through neighboring points */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < numOfNeighs; i++) {
|
|
|
|
int n_index = sData->adj_data->n_index[index] + i;
|
2012-01-24 17:28:50 +00:00
|
|
|
float w_factor;
|
2011-07-02 18:06:39 +00:00
|
|
|
PaintPoint *ePoint = &prevPoint[sData->adj_data->n_target[n_index]];
|
2012-05-12 16:11:34 +00:00
|
|
|
float speed_scale = (bNeighs[n_index].dist < eff_scale) ? 1.0f : eff_scale / bNeighs[n_index].dist;
|
|
|
|
float color_mix = (MIN3(ePoint->wetness, pPoint->wetness, 1.0f)) * 0.25f * surface->color_spread_speed;
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
/* do color mixing */
|
2012-01-16 17:18:07 +00:00
|
|
|
if (color_mix) mixColors(pPoint->e_color, pPoint->e_alpha, ePoint->e_color, ePoint->e_alpha, color_mix);
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2012-01-16 17:18:07 +00:00
|
|
|
/* Only continue if surrounding point has higher wetness */
|
2012-05-12 16:11:34 +00:00
|
|
|
if (ePoint->wetness < pPoint->wetness || ePoint->wetness < MIN_WETNESS) continue;
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2012-09-30 06:12:47 +00:00
|
|
|
w_factor = 1.0f / numOfNeighs * MIN2(ePoint->wetness, 1.0f) * speed_scale;
|
2012-01-16 17:18:07 +00:00
|
|
|
CLAMP(w_factor, 0.0f, 1.0f);
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2012-01-16 17:18:07 +00:00
|
|
|
/* mix new wetness and color */
|
2012-05-12 16:11:34 +00:00
|
|
|
pPoint->wetness = (1.0f - w_factor) * pPoint->wetness + w_factor * ePoint->wetness;
|
2012-01-16 17:18:07 +00:00
|
|
|
pPoint->e_alpha = mixColors(pPoint->e_color, pPoint->e_alpha, ePoint->e_color, ePoint->e_alpha, w_factor);
|
2011-06-27 07:30:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-03-09 18:28:30 +00:00
|
|
|
* Shrink Effect
|
|
|
|
*/
|
2012-02-27 10:35:39 +00:00
|
|
|
if (surface->effect & MOD_DPAINT_EFFECT_DO_SHRINK) {
|
2012-05-12 16:11:34 +00:00
|
|
|
float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->shrink_speed * timescale;
|
2011-06-27 07:30:58 +00:00
|
|
|
|
|
|
|
/* Copy current surface to the previous points array to read unmodified values */
|
2012-05-12 16:11:34 +00:00
|
|
|
memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-04-28 06:31:57 +00:00
|
|
|
for (index = 0; index < sData->total_points; index++) {
|
2011-06-27 07:30:58 +00:00
|
|
|
int i;
|
2011-07-08 11:03:37 +00:00
|
|
|
int numOfNeighs = sData->adj_data->n_num[index];
|
2011-06-27 07:30:58 +00:00
|
|
|
float totalAlpha = 0.0f;
|
2012-05-12 16:11:34 +00:00
|
|
|
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < numOfNeighs; i++) {
|
|
|
|
int n_index = sData->adj_data->n_index[index] + i;
|
|
|
|
float speed_scale = (bNeighs[n_index].dist < eff_scale) ? 1.0f : eff_scale / bNeighs[n_index].dist;
|
2011-07-02 18:06:39 +00:00
|
|
|
PaintPoint *ePoint = &prevPoint[sData->adj_data->n_target[n_index]];
|
2011-06-27 07:30:58 +00:00
|
|
|
float a_factor, ea_factor, w_factor;
|
|
|
|
|
|
|
|
totalAlpha += ePoint->e_alpha;
|
|
|
|
|
2012-03-01 12:20:18 +00:00
|
|
|
/* Check if neighboring point has lower alpha,
|
2012-03-09 18:28:30 +00:00
|
|
|
* if so, decrease this point's alpha as well*/
|
2011-06-27 07:30:58 +00:00
|
|
|
if (pPoint->alpha <= 0.0f && pPoint->e_alpha <= 0.0f && pPoint->wetness <= 0.0f) continue;
|
|
|
|
|
|
|
|
/* decrease factor for dry paint alpha */
|
2012-05-12 16:11:34 +00:00
|
|
|
a_factor = (1.0f - ePoint->alpha) / numOfNeighs * (pPoint->alpha - ePoint->alpha) * speed_scale;
|
2011-06-27 07:30:58 +00:00
|
|
|
if (a_factor < 0.0f) a_factor = 0.0f;
|
|
|
|
/* decrease factor for wet paint alpha */
|
2012-05-12 16:11:34 +00:00
|
|
|
ea_factor = (1.0f - ePoint->e_alpha) / 8 * (pPoint->e_alpha - ePoint->e_alpha) * speed_scale;
|
2011-06-27 07:30:58 +00:00
|
|
|
if (ea_factor < 0.0f) ea_factor = 0.0f;
|
|
|
|
/* decrease factor for paint wetness */
|
2012-05-12 16:11:34 +00:00
|
|
|
w_factor = (1.0f - ePoint->wetness) / 8 * (pPoint->wetness - ePoint->wetness) * speed_scale;
|
2011-06-27 07:30:58 +00:00
|
|
|
if (w_factor < 0.0f) w_factor = 0.0f;
|
|
|
|
|
2011-07-24 17:40:02 +00:00
|
|
|
pPoint->alpha -= a_factor;
|
|
|
|
if (pPoint->alpha < 0.0f) pPoint->alpha = 0.0f;
|
|
|
|
pPoint->e_alpha -= ea_factor;
|
|
|
|
if (pPoint->e_alpha < 0.0f) pPoint->e_alpha = 0.0f;
|
|
|
|
pPoint->wetness -= w_factor;
|
|
|
|
if (pPoint->wetness < 0.0f) pPoint->wetness = 0.0f;
|
2011-06-27 07:30:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-03-09 18:28:30 +00:00
|
|
|
* Drip Effect
|
|
|
|
*/
|
2012-04-28 06:31:57 +00:00
|
|
|
if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP && force) {
|
2012-05-12 16:11:34 +00:00
|
|
|
float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * timescale / 2.0f;
|
2011-08-03 18:31:48 +00:00
|
|
|
/* Copy current surface to the previous points array to read unmodified values */
|
2012-05-12 16:11:34 +00:00
|
|
|
memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
|
2011-08-03 18:31:48 +00:00
|
|
|
|
2011-07-02 18:06:39 +00:00
|
|
|
for (index = 0; index < sData->total_points; index++) {
|
|
|
|
int i;
|
2012-05-12 16:11:34 +00:00
|
|
|
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
|
2011-08-03 18:31:48 +00:00
|
|
|
PaintPoint *pPoint_prev = &prevPoint[index];
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
int closest_id[2];
|
|
|
|
float closest_d[2];
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2011-07-02 18:06:39 +00:00
|
|
|
/* adjust drip speed depending on wetness */
|
2012-01-16 17:18:07 +00:00
|
|
|
float w_factor = pPoint_prev->wetness - 0.025f;
|
2011-07-02 18:06:39 +00:00
|
|
|
if (w_factor <= 0) continue;
|
2012-01-16 17:18:07 +00:00
|
|
|
CLAMP(w_factor, 0.0f, 1.0f);
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* get force affect points */
|
2012-05-12 16:11:34 +00:00
|
|
|
surface_determineForceTargetPoints(sData, index, &force[index * 4], closest_d, closest_id);
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2011-07-02 18:06:39 +00:00
|
|
|
/* Apply movement towards those two points */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < 2; i++) {
|
2011-07-02 18:06:39 +00:00
|
|
|
int n_index = closest_id[i];
|
2012-05-12 16:11:34 +00:00
|
|
|
if (n_index != -1 && closest_d[i] > 0.0f) {
|
2012-01-16 17:18:07 +00:00
|
|
|
float dir_dot = closest_d[i], dir_factor, a_factor;
|
2012-05-12 16:11:34 +00:00
|
|
|
float speed_scale = eff_scale * force[index * 4 + 3] / bNeighs[n_index].dist;
|
|
|
|
PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[sData->adj_data->n_target[n_index]];
|
2012-01-16 17:18:07 +00:00
|
|
|
float e_wet = ePoint->wetness;
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2011-07-02 18:06:39 +00:00
|
|
|
/* just skip if angle is too extreme */
|
|
|
|
if (dir_dot <= 0.0f) continue;
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2012-01-16 17:18:07 +00:00
|
|
|
dir_factor = dir_dot * MIN2(speed_scale, 1.0f) * w_factor;
|
|
|
|
if (dir_factor > 0.5f) dir_factor = 0.5f;
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2012-08-17 14:43:20 +00:00
|
|
|
/* mix new wetness */
|
2011-07-02 18:06:39 +00:00
|
|
|
ePoint->wetness += dir_factor;
|
2012-01-16 17:18:07 +00:00
|
|
|
CLAMP(ePoint->wetness, 0.0f, MAX_WETNESS);
|
|
|
|
|
|
|
|
/* mix new color */
|
|
|
|
a_factor = dir_factor / pPoint_prev->wetness;
|
|
|
|
CLAMP(a_factor, 0.0f, 1.0f);
|
|
|
|
mixColors(ePoint->e_color, ePoint->e_alpha, pPoint_prev->e_color, pPoint_prev->e_alpha, a_factor);
|
|
|
|
/* dripping is supposed to preserve alpha level */
|
|
|
|
if (pPoint_prev->e_alpha > ePoint->e_alpha) {
|
|
|
|
ePoint->e_alpha += a_factor * pPoint_prev->e_alpha;
|
|
|
|
if (ePoint->e_alpha > pPoint_prev->e_alpha)
|
|
|
|
ePoint->e_alpha = pPoint_prev->e_alpha;
|
|
|
|
}
|
2011-07-02 18:06:39 +00:00
|
|
|
|
2012-01-16 17:18:07 +00:00
|
|
|
/* decrease paint wetness on current point */
|
|
|
|
pPoint->wetness -= (ePoint->wetness - e_wet);
|
|
|
|
CLAMP(pPoint->wetness, 0.0f, MAX_WETNESS);
|
2011-06-27 07:30:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-09-15 01:52:28 +00:00
|
|
|
static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescale)
|
2011-07-02 18:06:39 +00:00
|
|
|
{
|
|
|
|
PaintSurfaceData *sData = surface->data;
|
2012-01-24 17:28:50 +00:00
|
|
|
BakeAdjPoint *bNeighs = sData->bData->bNeighs;
|
2011-07-02 18:06:39 +00:00
|
|
|
int index;
|
|
|
|
int steps, ss;
|
|
|
|
float dt, min_dist, damp_factor;
|
|
|
|
float wave_speed = surface->wave_speed;
|
2013-08-03 09:46:38 +00:00
|
|
|
float wave_max_slope = (surface->wave_smoothness >= 0.01f) ? (0.5f / surface->wave_smoothness) : 0.0f;
|
2011-07-02 18:06:39 +00:00
|
|
|
double average_dist = 0.0f;
|
2012-12-21 05:07:26 +00:00
|
|
|
const float canvas_size = getSurfaceDimension(sData);
|
2012-05-12 16:11:34 +00:00
|
|
|
float wave_scale = CANVAS_REL_SIZE / canvas_size;
|
2011-07-02 18:06:39 +00:00
|
|
|
|
|
|
|
/* allocate memory */
|
2012-05-12 16:11:34 +00:00
|
|
|
PaintWavePoint *prevPoint = MEM_mallocN(sData->total_points * sizeof(PaintWavePoint), "Temp previous points for wave simulation");
|
2011-07-02 18:06:39 +00:00
|
|
|
if (!prevPoint) return;
|
|
|
|
|
|
|
|
/* calculate average neigh distance (single thread) */
|
2012-04-28 06:31:57 +00:00
|
|
|
for (index = 0; index < sData->total_points; index++) {
|
2011-07-02 18:06:39 +00:00
|
|
|
int i;
|
2011-07-08 11:03:37 +00:00
|
|
|
int numOfNeighs = sData->adj_data->n_num[index];
|
2011-07-02 18:06:39 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < numOfNeighs; i++) {
|
|
|
|
average_dist += bNeighs[sData->adj_data->n_index[index] + i].dist;
|
2011-07-02 18:06:39 +00:00
|
|
|
}
|
|
|
|
}
|
2012-05-12 16:11:34 +00:00
|
|
|
average_dist *= wave_scale / sData->adj_data->total_targets;
|
2011-07-02 18:06:39 +00:00
|
|
|
|
|
|
|
/* determine number of required steps */
|
2012-05-12 16:11:34 +00:00
|
|
|
steps = (int)ceil((WAVE_TIME_FAC * timescale * surface->wave_timescale) / (average_dist / wave_speed / 3));
|
2011-11-16 18:32:28 +00:00
|
|
|
CLAMP(steps, 1, 20);
|
2011-07-02 18:06:39 +00:00
|
|
|
timescale /= steps;
|
|
|
|
|
|
|
|
/* apply simulation values for final timescale */
|
2012-05-12 16:11:34 +00:00
|
|
|
dt = WAVE_TIME_FAC * timescale * surface->wave_timescale;
|
|
|
|
min_dist = wave_speed * dt * 1.5f;
|
|
|
|
damp_factor = pow((1.0f - surface->wave_damping), timescale * surface->wave_timescale);
|
2011-07-02 18:06:39 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
for (ss = 0; ss < steps; ss++) {
|
2011-07-02 18:06:39 +00:00
|
|
|
|
|
|
|
/* copy previous frame data */
|
2012-05-12 16:11:34 +00:00
|
|
|
memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(PaintWavePoint));
|
2011-07-02 18:06:39 +00:00
|
|
|
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2011-07-02 18:06:39 +00:00
|
|
|
for (index = 0; index < sData->total_points; index++) {
|
2012-05-12 16:11:34 +00:00
|
|
|
PaintWavePoint *wPoint = &((PaintWavePoint *)sData->type_data)[index];
|
2011-07-08 11:03:37 +00:00
|
|
|
int numOfNeighs = sData->adj_data->n_num[index];
|
2013-08-03 09:46:38 +00:00
|
|
|
float force = 0.0f, avg_dist = 0.0f, avg_height = 0.0f, avg_n_height = 0.0f;
|
2011-07-02 18:06:39 +00:00
|
|
|
int numOfN = 0, numOfRN = 0;
|
|
|
|
int i;
|
|
|
|
|
2011-11-16 18:32:28 +00:00
|
|
|
if (wPoint->state > 0) continue;
|
2011-07-02 18:06:39 +00:00
|
|
|
|
|
|
|
/* calculate force from surrounding points */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < numOfNeighs; i++) {
|
|
|
|
int n_index = sData->adj_data->n_index[index] + i;
|
|
|
|
float dist = bNeighs[n_index].dist * wave_scale;
|
2011-07-02 18:06:39 +00:00
|
|
|
PaintWavePoint *tPoint = &prevPoint[sData->adj_data->n_target[n_index]];
|
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
if (!dist || tPoint->state > 0) continue;
|
|
|
|
if (dist < min_dist) dist = min_dist;
|
2011-07-02 18:06:39 +00:00
|
|
|
avg_dist += dist;
|
|
|
|
numOfN++;
|
|
|
|
|
|
|
|
/* count average height for edge points for open borders */
|
|
|
|
if (!(sData->adj_data->flags[sData->adj_data->n_target[n_index]] & ADJ_ON_MESH_EDGE)) {
|
2013-08-03 09:46:38 +00:00
|
|
|
avg_n_height += tPoint->height;
|
2011-07-02 18:06:39 +00:00
|
|
|
numOfRN++;
|
|
|
|
}
|
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
force += (tPoint->height - wPoint->height) / (dist * dist);
|
2013-08-03 09:46:38 +00:00
|
|
|
avg_height += tPoint->height;
|
2011-07-02 18:06:39 +00:00
|
|
|
}
|
2012-05-12 16:11:34 +00:00
|
|
|
avg_dist = (numOfN) ? avg_dist / numOfN : 0.0f;
|
2011-07-02 18:06:39 +00:00
|
|
|
|
|
|
|
if (surface->flags & MOD_DPAINT_WAVE_OPEN_BORDERS &&
|
2012-05-20 19:49:27 +00:00
|
|
|
sData->adj_data->flags[index] & ADJ_ON_MESH_EDGE)
|
|
|
|
{
|
2011-07-02 18:06:39 +00:00
|
|
|
/* if open borders, apply a fake height to keep waves going on */
|
2013-08-03 09:46:38 +00:00
|
|
|
avg_n_height = (numOfRN) ? avg_n_height / numOfRN : 0.0f;
|
|
|
|
wPoint->height = (dt * wave_speed * avg_n_height + wPoint->height * avg_dist) / (avg_dist + dt * wave_speed);
|
2011-07-02 18:06:39 +00:00
|
|
|
}
|
2011-09-05 16:04:15 +00:00
|
|
|
/* else do wave eq */
|
2011-07-02 18:06:39 +00:00
|
|
|
else {
|
|
|
|
/* add force towards zero height based on average dist */
|
|
|
|
if (avg_dist)
|
2012-05-12 16:11:34 +00:00
|
|
|
force += (0.0f - wPoint->height) * surface->wave_spring / (avg_dist * avg_dist) / 2.0f;
|
2011-07-02 18:06:39 +00:00
|
|
|
|
|
|
|
/* change point velocity */
|
2012-05-12 16:11:34 +00:00
|
|
|
wPoint->velocity += force * dt * wave_speed * wave_speed;
|
2011-07-02 18:06:39 +00:00
|
|
|
/* damping */
|
|
|
|
wPoint->velocity *= damp_factor;
|
|
|
|
/* and new height */
|
2012-05-12 16:11:34 +00:00
|
|
|
wPoint->height += wPoint->velocity * dt;
|
2013-08-03 09:46:38 +00:00
|
|
|
|
|
|
|
/* limit wave slope steepness */
|
|
|
|
if (wave_max_slope && avg_dist) {
|
|
|
|
float max_offset = wave_max_slope * avg_dist;
|
|
|
|
float offset = (numOfN) ? (avg_height / numOfN - wPoint->height) : 0.0f;
|
|
|
|
if (offset > max_offset) wPoint->height += offset - max_offset;
|
|
|
|
if (offset < -max_offset) wPoint->height += offset + max_offset;
|
|
|
|
}
|
2011-07-02 18:06:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* reset state */
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2011-07-02 18:06:39 +00:00
|
|
|
for (index = 0; index < sData->total_points; index++) {
|
2012-05-12 16:11:34 +00:00
|
|
|
PaintWavePoint *wPoint = &((PaintWavePoint *)sData->type_data)[index];
|
2011-11-16 18:32:28 +00:00
|
|
|
/* if there wasnt any brush intersection, clear isect height */
|
|
|
|
if (wPoint->state == DPAINT_WAVE_NONE) {
|
|
|
|
wPoint->brush_isect = 0.0f;
|
|
|
|
}
|
2011-10-28 14:46:09 +00:00
|
|
|
wPoint->state = DPAINT_WAVE_NONE;
|
2011-07-02 18:06:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
MEM_freeN(prevPoint);
|
|
|
|
}
|
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
/* Do dissolve and fading effects */
|
2011-08-21 19:03:47 +00:00
|
|
|
static void dynamicPaint_surfacePreStep(DynamicPaintSurface *surface, float timescale)
|
|
|
|
{
|
2011-06-16 10:41:00 +00:00
|
|
|
PaintSurfaceData *sData = surface->data;
|
|
|
|
int index;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-05-12 16:11:34 +00:00
|
|
|
for (index = 0; index < sData->total_points; index++) {
|
2011-06-16 10:41:00 +00:00
|
|
|
/* Do drying dissolve effects */
|
|
|
|
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
|
2012-05-12 16:11:34 +00:00
|
|
|
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
|
2011-06-16 10:41:00 +00:00
|
|
|
/* drying */
|
2012-01-16 17:18:07 +00:00
|
|
|
if (surface->flags & MOD_DPAINT_USE_DRYING) {
|
|
|
|
if (pPoint->wetness >= MIN_WETNESS) {
|
|
|
|
int i;
|
|
|
|
float dry_ratio, f_color[4];
|
|
|
|
float p_wetness = pPoint->wetness;
|
2012-11-04 06:21:09 +00:00
|
|
|
value_dissolve(&pPoint->wetness, surface->dry_speed, timescale, (surface->flags & MOD_DPAINT_DRY_LOG));
|
2012-05-12 16:11:34 +00:00
|
|
|
if (pPoint->wetness < 0.0f) pPoint->wetness = 0.0f;
|
2011-06-16 10:41:00 +00:00
|
|
|
|
2012-01-16 17:18:07 +00:00
|
|
|
if (pPoint->wetness < surface->color_dry_threshold) {
|
2012-05-12 16:11:34 +00:00
|
|
|
dry_ratio = pPoint->wetness / p_wetness;
|
2012-01-16 17:18:07 +00:00
|
|
|
|
|
|
|
/*
|
2012-03-09 18:28:30 +00:00
|
|
|
* Slowly "shift" paint from wet layer to dry layer as it drys:
|
|
|
|
*/
|
2012-01-16 17:18:07 +00:00
|
|
|
/* make sure alpha values are within proper range */
|
|
|
|
CLAMP(pPoint->alpha, 0.0f, 1.0f);
|
|
|
|
CLAMP(pPoint->e_alpha, 0.0f, 1.0f);
|
|
|
|
|
|
|
|
/* get current final blended color of these layers */
|
|
|
|
blendColors(pPoint->color, pPoint->alpha, pPoint->e_color, pPoint->e_alpha, f_color);
|
|
|
|
/* reduce wet layer alpha by dry factor */
|
|
|
|
pPoint->e_alpha *= dry_ratio;
|
|
|
|
|
|
|
|
/* now calculate new alpha for dry layer that keeps final blended color unchanged */
|
2012-05-12 16:11:34 +00:00
|
|
|
pPoint->alpha = (f_color[3] - pPoint->e_alpha) / (1.0f - pPoint->e_alpha);
|
2012-01-16 17:18:07 +00:00
|
|
|
/* for each rgb component, calculate a new dry layer color that keeps the final blend color
|
2012-03-09 18:28:30 +00:00
|
|
|
* with these new alpha values. (wet layer color doesnt change)*/
|
2012-01-16 17:18:07 +00:00
|
|
|
if (pPoint->alpha) {
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
pPoint->color[i] = (f_color[i] * f_color[3] - pPoint->e_color[i] * pPoint->e_alpha) / (pPoint->alpha * (1.0f - pPoint->e_alpha));
|
2012-01-16 17:18:07 +00:00
|
|
|
}
|
|
|
|
}
|
2011-11-05 07:39:59 +00:00
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
|
2012-01-16 17:18:07 +00:00
|
|
|
pPoint->state = DPAINT_PAINT_WET;
|
|
|
|
}
|
|
|
|
/* in case of just dryed paint, just mix it to the dry layer and mark it empty */
|
|
|
|
else if (pPoint->state > 0) {
|
|
|
|
float f_color[4];
|
|
|
|
blendColors(pPoint->color, pPoint->alpha, pPoint->e_color, pPoint->e_alpha, f_color);
|
|
|
|
copy_v3_v3(pPoint->color, f_color);
|
|
|
|
pPoint->alpha = f_color[3];
|
|
|
|
/* clear wet layer */
|
|
|
|
pPoint->wetness = 0.0f;
|
|
|
|
pPoint->e_alpha = 0.0f;
|
|
|
|
pPoint->state = DPAINT_PAINT_DRY;
|
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
if (surface->flags & MOD_DPAINT_DISSOLVE) {
|
2012-11-04 06:21:09 +00:00
|
|
|
value_dissolve(&pPoint->alpha, surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG));
|
2011-06-16 10:41:00 +00:00
|
|
|
if (pPoint->alpha < 0.0f) pPoint->alpha = 0.0f;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-11-04 06:21:09 +00:00
|
|
|
value_dissolve(&pPoint->e_alpha, surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG));
|
2011-06-16 10:41:00 +00:00
|
|
|
if (pPoint->e_alpha < 0.0f) pPoint->e_alpha = 0.0f;
|
|
|
|
}
|
|
|
|
}
|
2011-06-18 18:41:20 +00:00
|
|
|
/* dissolve for float types */
|
|
|
|
else if (surface->flags & MOD_DPAINT_DISSOLVE &&
|
2012-05-12 16:11:34 +00:00
|
|
|
(surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
|
2012-05-20 19:49:27 +00:00
|
|
|
surface->type == MOD_DPAINT_SURFACE_T_WEIGHT))
|
|
|
|
{
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
float *point = &((float *)sData->type_data)[index];
|
2011-06-18 18:41:20 +00:00
|
|
|
/* log or linear */
|
2012-11-04 06:21:09 +00:00
|
|
|
value_dissolve(point, surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG));
|
2011-06-18 18:41:20 +00:00
|
|
|
if (*point < 0.0f) *point = 0.0f;
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
2011-07-22 18:37:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *ob)
|
|
|
|
{
|
|
|
|
PaintSurfaceData *sData = surface->data;
|
|
|
|
PaintBakeData *bData = sData->bData;
|
|
|
|
DerivedMesh *dm = surface->canvas->dm;
|
|
|
|
MVert *mvert = dm->getVertArray(dm);
|
|
|
|
|
|
|
|
int numOfVerts = dm->getNumVerts(dm);
|
|
|
|
int i;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (!bData->prev_verts) return 1;
|
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* matrix comparison */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < 4; i++) {
|
2011-07-22 18:37:30 +00:00
|
|
|
int j;
|
2012-05-12 16:11:34 +00:00
|
|
|
for (j = 0; j < 4; j++)
|
|
|
|
if (bData->prev_obmat[i][j] != ob->obmat[i][j]) return 1;
|
2011-07-22 18:37:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* vertices */
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-05-12 16:11:34 +00:00
|
|
|
for (i = 0; i < numOfVerts; i++) {
|
2011-07-22 18:37:30 +00:00
|
|
|
int j;
|
2012-05-12 16:11:34 +00:00
|
|
|
for (j = 0; j < 3; j++)
|
2011-07-22 18:37:30 +00:00
|
|
|
if (bData->prev_verts[i].co[j] != mvert[i].co[j]) {
|
|
|
|
ret = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-05 09:31:35 +00:00
|
|
|
return ret;
|
2011-07-22 18:37:30 +00:00
|
|
|
}
|
|
|
|
|
2011-11-11 10:46:26 +00:00
|
|
|
static int surface_needsVelocityData(DynamicPaintSurface *surface, Scene *scene)
|
2011-08-03 18:31:48 +00:00
|
|
|
{
|
|
|
|
if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP)
|
|
|
|
return 1;
|
|
|
|
|
2011-11-10 13:00:27 +00:00
|
|
|
if (surface_getBrushFlags(surface, scene) & BRUSH_USES_VELOCITY)
|
2011-08-03 18:31:48 +00:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int surface_needsAccelerationData(DynamicPaintSurface *surface)
|
|
|
|
{
|
|
|
|
if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
/* Prepare for surface step by creating PaintBakeNormal data */
|
2011-08-03 18:31:48 +00:00
|
|
|
static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, Scene *scene, Object *ob)
|
2011-07-22 18:37:30 +00:00
|
|
|
{
|
|
|
|
PaintSurfaceData *sData = surface->data;
|
|
|
|
PaintAdjData *adj_data = sData->adj_data;
|
|
|
|
PaintBakeData *bData = sData->bData;
|
|
|
|
DerivedMesh *dm = surface->canvas->dm;
|
2011-08-03 18:31:48 +00:00
|
|
|
int index, new_bdata = 0;
|
2011-11-11 10:46:26 +00:00
|
|
|
int do_velocity_data = surface_needsVelocityData(surface, scene);
|
2011-08-03 18:31:48 +00:00
|
|
|
int do_accel_data = surface_needsAccelerationData(surface);
|
2011-07-22 18:37:30 +00:00
|
|
|
|
|
|
|
int canvasNumOfVerts = dm->getNumVerts(dm);
|
|
|
|
MVert *mvert = dm->getVertArray(dm);
|
|
|
|
Vec3f *canvas_verts;
|
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
if (bData) {
|
|
|
|
int surface_moved = dynamicPaint_surfaceHasMoved(surface, ob);
|
|
|
|
|
|
|
|
/* get previous speed for accelertaion */
|
|
|
|
if (do_accel_data && bData->prev_velocity && bData->velocity)
|
2012-05-12 16:11:34 +00:00
|
|
|
memcpy(bData->prev_velocity, bData->velocity, sData->total_points * sizeof(Vec3f));
|
2011-08-03 18:31:48 +00:00
|
|
|
|
|
|
|
/* reset speed vectors */
|
|
|
|
if (do_velocity_data && bData->velocity && (bData->clear || !surface_moved))
|
2012-05-12 16:11:34 +00:00
|
|
|
memset(bData->velocity, 0, sData->total_points * sizeof(Vec3f));
|
2011-08-03 18:31:48 +00:00
|
|
|
|
|
|
|
/* if previous data exists and mesh hasn't moved, no need to recalc */
|
|
|
|
if (!surface_moved)
|
|
|
|
return 1;
|
|
|
|
}
|
2011-07-22 18:37:30 +00:00
|
|
|
|
2012-05-12 16:11:34 +00:00
|
|
|
canvas_verts = (struct Vec3f *) MEM_mallocN(canvasNumOfVerts * sizeof(struct Vec3f), "Dynamic Paint transformed canvas verts");
|
2011-07-22 18:37:30 +00:00
|
|
|
if (!canvas_verts) return 0;
|
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
/* allocate memory if required */
|
2011-07-22 18:37:30 +00:00
|
|
|
if (!bData) {
|
|
|
|
sData->bData = bData = (struct PaintBakeData *) MEM_callocN(sizeof(struct PaintBakeData), "Dynamic Paint bake data");
|
|
|
|
if (!bData) {
|
|
|
|
if (canvas_verts) MEM_freeN(canvas_verts);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Init bdata */
|
2012-05-12 16:11:34 +00:00
|
|
|
bData->bNormal = (struct PaintBakeNormal *) MEM_mallocN(sData->total_points * sizeof(struct PaintBakeNormal), "Dynamic Paint step data");
|
|
|
|
bData->s_pos = MEM_mallocN(sData->total_points * sizeof(unsigned int), "Dynamic Paint bData s_pos");
|
|
|
|
bData->s_num = MEM_mallocN(sData->total_points * sizeof(unsigned int), "Dynamic Paint bData s_num");
|
|
|
|
bData->realCoord = (struct Vec3f *) MEM_mallocN(surface_totalSamples(surface) * sizeof(Vec3f), "Dynamic Paint point coords");
|
|
|
|
bData->prev_verts = MEM_mallocN(canvasNumOfVerts * sizeof(MVert), "Dynamic Paint bData prev_verts");
|
2011-07-22 18:37:30 +00:00
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* if any allocation failed, free everything */
|
2011-07-22 18:37:30 +00:00
|
|
|
if (!bData->bNormal || !bData->s_pos || !bData->s_num || !bData->realCoord || !canvas_verts) {
|
|
|
|
if (bData->bNormal) MEM_freeN(bData->bNormal);
|
|
|
|
if (bData->s_pos) MEM_freeN(bData->s_pos);
|
|
|
|
if (bData->s_num) MEM_freeN(bData->s_num);
|
|
|
|
if (bData->realCoord) MEM_freeN(bData->realCoord);
|
|
|
|
if (canvas_verts) MEM_freeN(canvas_verts);
|
|
|
|
|
2012-10-26 17:32:50 +00:00
|
|
|
return setError(surface->canvas, N_("Not enough free memory"));
|
2011-07-22 18:37:30 +00:00
|
|
|
}
|
2011-08-03 18:31:48 +00:00
|
|
|
|
|
|
|
new_bdata = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (do_velocity_data && !bData->velocity) {
|
2012-05-12 16:11:34 +00:00
|
|
|
bData->velocity = (struct Vec3f *) MEM_callocN(sData->total_points * sizeof(Vec3f), "Dynamic Paint velocity");
|
2011-08-03 18:31:48 +00:00
|
|
|
}
|
|
|
|
if (do_accel_data && !bData->prev_velocity) {
|
2012-05-12 16:11:34 +00:00
|
|
|
bData->prev_velocity = (struct Vec3f *) MEM_mallocN(sData->total_points * sizeof(Vec3f), "Dynamic Paint prev velocity");
|
2011-08-03 18:31:48 +00:00
|
|
|
/* copy previous vel */
|
|
|
|
if (bData->prev_velocity && bData->velocity)
|
2012-05-12 16:11:34 +00:00
|
|
|
memcpy(bData->prev_velocity, bData->velocity, sData->total_points * sizeof(Vec3f));
|
2011-07-22 18:37:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-03-09 18:28:30 +00:00
|
|
|
* Make a transformed copy of canvas derived mesh vertices to avoid recalculation.
|
|
|
|
*/
|
2011-11-16 18:32:28 +00:00
|
|
|
bData->mesh_bounds.valid = 0;
|
2012-05-12 16:11:34 +00:00
|
|
|
for (index = 0; index < canvasNumOfVerts; index++) {
|
2011-10-28 14:46:09 +00:00
|
|
|
copy_v3_v3(canvas_verts[index].v, mvert[index].co);
|
2011-07-22 18:37:30 +00:00
|
|
|
mul_m4_v3(ob->obmat, canvas_verts[index].v);
|
2011-11-16 18:32:28 +00:00
|
|
|
boundInsert(&bData->mesh_bounds, canvas_verts[index].v);
|
2011-07-22 18:37:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-03-09 18:28:30 +00:00
|
|
|
* Prepare each surface point for a new step
|
|
|
|
*/
|
2013-12-22 14:11:10 +11:00
|
|
|
#pragma omp parallel for schedule(static)
|
2012-05-12 16:11:34 +00:00
|
|
|
for (index = 0; index < sData->total_points; index++) {
|
2011-12-17 16:22:08 +00:00
|
|
|
float prev_point[3] = {0.0f, 0.0f, 0.0f};
|
2011-08-03 18:31:48 +00:00
|
|
|
if (do_velocity_data && !new_bdata) {
|
2011-10-28 14:46:09 +00:00
|
|
|
copy_v3_v3(prev_point, bData->realCoord[bData->s_pos[index]].v);
|
2011-08-03 18:31:48 +00:00
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
/*
|
2012-03-09 18:28:30 +00:00
|
|
|
* Calculate current 3D-position and normal of each surface point
|
|
|
|
*/
|
2011-06-16 10:41:00 +00:00
|
|
|
if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
|
|
|
|
float n1[3], n2[3], n3[3];
|
2012-05-12 16:11:34 +00:00
|
|
|
ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
|
|
|
|
PaintUVPoint *tPoint = &((PaintUVPoint *)f_data->uv_p)[index];
|
2011-06-17 18:04:56 +00:00
|
|
|
int ss;
|
2011-06-16 10:41:00 +00:00
|
|
|
|
2011-07-08 11:03:37 +00:00
|
|
|
bData->s_num[index] = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
|
2011-07-22 18:37:30 +00:00
|
|
|
bData->s_pos[index] = index * bData->s_num[index];
|
2011-07-08 11:03:37 +00:00
|
|
|
|
2011-06-17 18:04:56 +00:00
|
|
|
/* per sample coordinates */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (ss = 0; ss < bData->s_num[index]; ss++) {
|
|
|
|
interp_v3_v3v3v3(bData->realCoord[bData->s_pos[index] + ss].v,
|
2012-04-29 17:11:40 +00:00
|
|
|
canvas_verts[tPoint->v1].v,
|
|
|
|
canvas_verts[tPoint->v2].v,
|
|
|
|
canvas_verts[tPoint->v3].v,
|
|
|
|
f_data->barycentricWeights[index * bData->s_num[index] + ss].v);
|
2011-06-17 18:04:56 +00:00
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
|
|
|
|
/* Calculate current pixel surface normal */
|
2011-07-22 18:37:30 +00:00
|
|
|
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);
|
|
|
|
|
2012-04-29 17:11:40 +00:00
|
|
|
interp_v3_v3v3v3(bData->bNormal[index].invNorm,
|
2012-05-12 16:11:34 +00:00
|
|
|
n1, n2, n3, f_data->barycentricWeights[index * bData->s_num[index]].v);
|
2011-07-22 18:37:30 +00:00
|
|
|
mul_mat3_m4_v3(ob->obmat, bData->bNormal[index].invNorm);
|
|
|
|
normalize_v3(bData->bNormal[index].invNorm);
|
|
|
|
negate_v3(bData->bNormal[index].invNorm);
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
|
2011-07-08 11:03:37 +00:00
|
|
|
int ss;
|
2011-07-22 18:37:30 +00:00
|
|
|
if (surface->flags & MOD_DPAINT_ANTIALIAS && adj_data) {
|
2012-05-12 16:11:34 +00:00
|
|
|
bData->s_num[index] = adj_data->n_num[index] + 1;
|
|
|
|
bData->s_pos[index] = adj_data->n_index[index] + index;
|
2011-07-08 11:03:37 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
bData->s_num[index] = 1;
|
2011-07-22 18:37:30 +00:00
|
|
|
bData->s_pos[index] = index;
|
2011-07-08 11:03:37 +00:00
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* calculate position for each sample */
|
2012-05-12 16:11:34 +00:00
|
|
|
for (ss = 0; ss < bData->s_num[index]; ss++) {
|
2011-07-08 11:03:37 +00:00
|
|
|
/* first sample is always point center */
|
2012-05-12 16:11:34 +00:00
|
|
|
copy_v3_v3(bData->realCoord[bData->s_pos[index] + ss].v, canvas_verts[index].v);
|
2011-07-08 11:03:37 +00:00
|
|
|
if (ss > 0) {
|
2012-05-12 16:11:34 +00:00
|
|
|
int t_index = adj_data->n_index[index] + (ss - 1);
|
2011-07-08 11:03:37 +00:00
|
|
|
/* get vertex position at 1/3 of each neigh edge */
|
2012-05-12 16:11:34 +00:00
|
|
|
mul_v3_fl(bData->realCoord[bData->s_pos[index] + ss].v, 2.0f / 3.0f);
|
|
|
|
madd_v3_v3fl(bData->realCoord[bData->s_pos[index] + ss].v, canvas_verts[adj_data->n_target[t_index]].v, 1.0f / 3.0f);
|
2011-07-08 11:03:37 +00:00
|
|
|
}
|
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
|
|
|
|
/* normal */
|
2011-07-22 18:37:30 +00:00
|
|
|
normal_short_to_float_v3(bData->bNormal[index].invNorm, mvert[index].no);
|
|
|
|
mul_mat3_m4_v3(ob->obmat, bData->bNormal[index].invNorm);
|
|
|
|
normalize_v3(bData->bNormal[index].invNorm);
|
|
|
|
negate_v3(bData->bNormal[index].invNorm);
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* Prepare surface normal directional scale to easily convert
|
2012-03-09 18:28:30 +00:00
|
|
|
* brush intersection amount between global and local space */
|
2011-07-02 18:06:39 +00:00
|
|
|
if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
|
2012-05-20 19:49:27 +00:00
|
|
|
surface->type == MOD_DPAINT_SURFACE_T_WAVE)
|
|
|
|
{
|
2011-06-16 10:41:00 +00:00
|
|
|
float temp_nor[3];
|
2011-07-22 18:37:30 +00:00
|
|
|
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
|
|
|
|
normal_short_to_float_v3(temp_nor, mvert[index].no);
|
|
|
|
normalize_v3(temp_nor);
|
|
|
|
}
|
|
|
|
else {
|
2011-08-03 18:31:48 +00:00
|
|
|
float n1[3], n2[3], n3[3];
|
2012-05-12 16:11:34 +00:00
|
|
|
ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
|
|
|
|
PaintUVPoint *tPoint = &((PaintUVPoint *)f_data->uv_p)[index];
|
2011-08-03 18:31:48 +00:00
|
|
|
|
|
|
|
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(temp_nor,
|
2012-05-12 16:11:34 +00:00
|
|
|
n1, n2, n3, f_data->barycentricWeights[index * bData->s_num[index]].v);
|
2011-07-22 18:37:30 +00:00
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
mul_v3_v3(temp_nor, ob->size);
|
2011-07-22 18:37:30 +00:00
|
|
|
bData->bNormal[index].normal_scale = len_v3(temp_nor);
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
2011-08-03 18:31:48 +00:00
|
|
|
|
|
|
|
/* calculate speed vector */
|
|
|
|
if (do_velocity_data && !new_bdata && !bData->clear) {
|
2011-10-28 14:46:09 +00:00
|
|
|
sub_v3_v3v3(bData->velocity[index].v, bData->realCoord[bData->s_pos[index]].v, prev_point);
|
2011-08-03 18:31:48 +00:00
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-27 07:30:58 +00:00
|
|
|
MEM_freeN(canvas_verts);
|
2011-07-22 18:37:30 +00:00
|
|
|
|
|
|
|
/* generate surface space partitioning grid */
|
|
|
|
surfaceGenerateGrid(surface);
|
2012-01-24 17:28:50 +00:00
|
|
|
/* calculate current frame adjacency point distances and global dirs */
|
|
|
|
dynamicPaint_prepareAdjacencyData(surface, 0);
|
2011-07-22 18:37:30 +00:00
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* Copy current frame vertices to check against in next frame */
|
2011-07-22 18:37:30 +00:00
|
|
|
copy_m4_m4(bData->prev_obmat, ob->obmat);
|
2012-05-12 16:11:34 +00:00
|
|
|
memcpy(bData->prev_verts, mvert, canvasNumOfVerts * sizeof(MVert));
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
bData->clear = 0;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
return 1;
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/*
|
2012-03-03 20:19:11 +00:00
|
|
|
* Do Dynamic Paint step. Paints scene brush objects of current state/frame to the surface.
|
|
|
|
*/
|
2011-06-16 10:41:00 +00:00
|
|
|
static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *surface, float timescale, float subframe)
|
|
|
|
{
|
|
|
|
PaintSurfaceData *sData = surface->data;
|
2011-07-22 18:37:30 +00:00
|
|
|
PaintBakeData *bData = sData->bData;
|
2011-06-16 10:41:00 +00:00
|
|
|
DynamicPaintCanvasSettings *canvas = surface->canvas;
|
2011-06-27 07:30:58 +00:00
|
|
|
int ret = 1;
|
2012-09-11 02:18:27 +00:00
|
|
|
if (sData->total_points < 1) return 0;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
dynamicPaint_surfacePreStep(surface, timescale);
|
2011-05-24 07:08:58 +00:00
|
|
|
/*
|
2012-03-03 20:19:11 +00:00
|
|
|
* Loop through surface's target paint objects and do painting
|
|
|
|
*/
|
2011-05-24 07:08:58 +00:00
|
|
|
{
|
2011-06-16 10:41:00 +00:00
|
|
|
Base *base = NULL;
|
2012-10-21 05:46:41 +00:00
|
|
|
GroupObject *go = NULL;
|
2011-06-16 10:41:00 +00:00
|
|
|
Object *brushObj = NULL;
|
2011-05-24 07:08:58 +00:00
|
|
|
ModifierData *md = NULL;
|
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/* backup current scene frame */
|
|
|
|
int scene_frame = scene->r.cfra;
|
|
|
|
float scene_subframe = scene->r.subframe;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/* either from group or from all objects */
|
2012-03-24 06:18:31 +00:00
|
|
|
if (surface->brush_group)
|
2011-06-16 10:41:00 +00:00
|
|
|
go = surface->brush_group->gobject.first;
|
|
|
|
else
|
|
|
|
base = scene->base.first;
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
while (base || go) {
|
2011-06-16 10:41:00 +00:00
|
|
|
brushObj = NULL;
|
|
|
|
/* select object */
|
2012-05-19 13:55:54 +00:00
|
|
|
if (surface->brush_group) {
|
2012-05-12 16:11:34 +00:00
|
|
|
if (go->ob) brushObj = go->ob;
|
2012-05-19 13:55:54 +00:00
|
|
|
}
|
|
|
|
else
|
2011-06-16 10:41:00 +00:00
|
|
|
brushObj = base->object;
|
|
|
|
|
2012-05-19 13:55:54 +00:00
|
|
|
if (!brushObj) {
|
2011-06-16 10:41:00 +00:00
|
|
|
/* skip item */
|
2012-03-24 06:18:31 +00:00
|
|
|
if (surface->brush_group) go = go->next;
|
2012-05-12 16:11:34 +00:00
|
|
|
else base = base->next;
|
2012-05-19 13:55:54 +00:00
|
|
|
continue;
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
|
|
|
|
2011-06-16 10:41:00 +00:00
|
|
|
/* next item */
|
2012-03-24 06:18:31 +00:00
|
|
|
if (surface->brush_group)
|
2011-06-16 10:41:00 +00:00
|
|
|
go = go->next;
|
|
|
|
else
|
2012-05-12 16:11:34 +00:00
|
|
|
base = base->next;
|
2011-06-16 10:41:00 +00:00
|
|
|
|
2011-05-24 07:08:58 +00:00
|
|
|
/* check if target has an active dp modifier */
|
2011-09-05 16:04:15 +00:00
|
|
|
md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
|
2012-04-28 06:31:57 +00:00
|
|
|
if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
|
2011-05-24 07:08:58 +00:00
|
|
|
DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md;
|
2011-09-05 16:04:15 +00:00
|
|
|
/* make sure we're dealing with a brush */
|
2012-04-28 06:31:57 +00:00
|
|
|
if (pmd2->brush) {
|
2011-06-16 10:41:00 +00:00
|
|
|
DynamicPaintBrushSettings *brush = pmd2->brush;
|
2013-08-07 03:36:05 +00:00
|
|
|
BrushMaterials bMats = {NULL};
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
/* calculate brush speed vectors if required */
|
2011-11-20 10:52:25 +00:00
|
|
|
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE) {
|
2012-05-12 16:11:34 +00:00
|
|
|
bData->brush_velocity = MEM_callocN(sData->total_points * sizeof(float) * 4, "Dynamic Paint brush velocity");
|
2011-08-03 18:31:48 +00:00
|
|
|
/* init adjacency data if not already */
|
|
|
|
if (!sData->adj_data)
|
|
|
|
dynamicPaint_initAdjacencyData(surface, 1);
|
|
|
|
if (!bData->bNeighs)
|
2012-01-24 17:28:50 +00:00
|
|
|
dynamicPaint_prepareAdjacencyData(surface, 1);
|
2011-08-03 18:31:48 +00:00
|
|
|
}
|
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* update object data on this subframe */
|
2011-06-16 10:41:00 +00:00
|
|
|
if (subframe) {
|
|
|
|
scene_setSubframe(scene, subframe);
|
2013-03-22 17:08:55 +00:00
|
|
|
subframe_updateObject(scene, brushObj, UPDATE_EVERYTHING, SUBFRAME_RECURSION, BKE_scene_frame_get(scene));
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
2011-09-05 16:04:15 +00:00
|
|
|
/* Prepare materials if required */
|
2011-11-09 15:46:53 +00:00
|
|
|
if (brush_usesMaterial(brush, scene))
|
2011-09-05 16:04:15 +00:00
|
|
|
dynamicPaint_updateBrushMaterials(brushObj, brush->mat, scene, &bMats);
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* Apply brush on the surface depending on it's collision type */
|
|
|
|
/* Particle brush: */
|
|
|
|
if (brush->collision == MOD_DPAINT_COL_PSYS) {
|
2012-10-27 17:19:55 +00:00
|
|
|
if (brush->psys && brush->psys->part && ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) &&
|
2012-05-20 19:49:27 +00:00
|
|
|
psys_check_enabled(brushObj, brush->psys))
|
|
|
|
{
|
2011-06-27 07:30:58 +00:00
|
|
|
|
|
|
|
/* Paint a particle system */
|
2012-05-05 14:33:36 +00:00
|
|
|
BKE_animsys_evaluate_animdata(scene, &brush->psys->part->id, brush->psys->part->adt, BKE_scene_frame_get(scene), ADT_RECALC_ANIM);
|
2011-11-10 13:00:27 +00:00
|
|
|
dynamicPaint_paintParticles(surface, brush->psys, brush, timescale);
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
2011-07-08 11:03:37 +00:00
|
|
|
}
|
2011-09-05 16:04:15 +00:00
|
|
|
/* Object center distance: */
|
2011-07-08 11:03:37 +00:00
|
|
|
else if (brush->collision == MOD_DPAINT_COL_POINT && brushObj != ob) {
|
2011-11-10 13:00:27 +00:00
|
|
|
dynamicPaint_paintSinglePoint(surface, brushObj->loc, brush, brushObj, &bMats, scene, timescale);
|
2011-07-08 11:03:37 +00:00
|
|
|
}
|
2011-09-05 16:04:15 +00:00
|
|
|
/* Mesh volume/proximity: */
|
|
|
|
else if (brushObj != ob) {
|
2011-11-10 13:00:27 +00:00
|
|
|
dynamicPaint_paintMesh(surface, brush, brushObj, &bMats, scene, timescale);
|
2011-06-16 10:41:00 +00:00
|
|
|
}
|
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* free temp material data */
|
2011-11-09 15:46:53 +00:00
|
|
|
if (brush_usesMaterial(brush, scene))
|
2011-09-05 16:04:15 +00:00
|
|
|
dynamicPaint_freeBrushMaterials(&bMats);
|
2011-08-03 18:31:48 +00:00
|
|
|
/* reset object to it's original state */
|
2011-06-16 10:41:00 +00:00
|
|
|
if (subframe) {
|
|
|
|
scene->r.cfra = scene_frame;
|
|
|
|
scene->r.subframe = scene_subframe;
|
2013-03-22 17:08:55 +00:00
|
|
|
subframe_updateObject(scene, brushObj, UPDATE_EVERYTHING, SUBFRAME_RECURSION, BKE_scene_frame_get(scene));
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
2011-08-03 18:31:48 +00:00
|
|
|
|
|
|
|
/* process special brush effects, like smudge */
|
|
|
|
if (bData->brush_velocity) {
|
2011-11-20 10:52:25 +00:00
|
|
|
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE)
|
2011-08-04 07:09:21 +00:00
|
|
|
dynamicPaint_doSmudge(surface, brush, timescale);
|
2011-08-03 18:31:48 +00:00
|
|
|
MEM_freeN(bData->brush_velocity);
|
|
|
|
bData->brush_velocity = NULL;
|
|
|
|
}
|
2011-09-05 16:04:15 +00:00
|
|
|
}
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
/* surfaces operations that use adjacency data */
|
2012-03-07 04:53:43 +00:00
|
|
|
if (sData->adj_data && bData->bNeighs) {
|
2011-07-22 18:37:30 +00:00
|
|
|
/* wave type surface simulation step */
|
|
|
|
if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
|
|
|
|
dynamicPaint_doWaveStep(surface, timescale);
|
|
|
|
}
|
2011-07-02 18:06:39 +00:00
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
/* paint surface effects */
|
2012-03-07 04:53:43 +00:00
|
|
|
if (surface->effect && surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
|
2011-07-22 18:37:30 +00:00
|
|
|
int steps = 1, s;
|
|
|
|
PaintPoint *prevPoint;
|
|
|
|
float *force = NULL;
|
2011-07-02 18:06:39 +00:00
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
/* Allocate memory for surface previous points to read unchanged values from */
|
2012-05-12 16:11:34 +00:00
|
|
|
prevPoint = MEM_mallocN(sData->total_points * sizeof(struct PaintPoint), "PaintSurfaceDataCopy");
|
2011-08-03 18:31:48 +00:00
|
|
|
if (!prevPoint)
|
2012-10-26 17:32:50 +00:00
|
|
|
return setError(canvas, N_("Not enough free memory"));
|
2011-06-27 07:30:58 +00:00
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
/* Prepare effects and get number of required steps */
|
|
|
|
steps = dynamicPaint_prepareEffectStep(surface, scene, ob, &force, timescale);
|
2011-09-05 16:04:15 +00:00
|
|
|
for (s = 0; s < steps; s++) {
|
2011-08-03 18:31:48 +00:00
|
|
|
dynamicPaint_doEffectStep(surface, force, prevPoint, timescale, (float)steps);
|
2011-07-02 18:06:39 +00:00
|
|
|
}
|
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
/* Free temporary effect data */
|
|
|
|
if (prevPoint) MEM_freeN(prevPoint);
|
|
|
|
if (force) MEM_freeN(force);
|
2011-07-02 18:06:39 +00:00
|
|
|
}
|
2011-06-27 07:30:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-03-03 20:19:11 +00:00
|
|
|
* Calculate a single frame and included subframes for surface
|
|
|
|
*/
|
2011-10-13 20:00:22 +00:00
|
|
|
int dynamicPaint_calculateFrame(DynamicPaintSurface *surface, Scene *scene, Object *cObject, int frame)
|
2011-05-24 07:08:58 +00:00
|
|
|
{
|
2011-06-16 10:41:00 +00:00
|
|
|
float timescale = 1.0f;
|
2011-07-22 18:37:30 +00:00
|
|
|
|
2011-08-05 09:31:35 +00:00
|
|
|
/* apply previous displace on derivedmesh if incremental surface */
|
|
|
|
if (surface->flags & MOD_DPAINT_DISP_INCREMENTAL)
|
2012-01-16 17:18:07 +00:00
|
|
|
dynamicPaint_applySurfaceDisplace(surface, surface->canvas->dm);
|
2011-08-05 09:31:35 +00:00
|
|
|
|
2011-07-22 18:37:30 +00:00
|
|
|
/* update bake data */
|
2011-08-03 18:31:48 +00:00
|
|
|
dynamicPaint_generateBakeData(surface, scene, cObject);
|
2011-06-16 10:41:00 +00:00
|
|
|
|
2012-03-18 07:38:51 +00:00
|
|
|
/* don't do substeps for first frame */
|
2011-06-16 10:41:00 +00:00
|
|
|
if (surface->substeps && (frame != surface->start_frame)) {
|
|
|
|
int st;
|
2012-05-12 16:11:34 +00:00
|
|
|
timescale = 1.0f / (surface->substeps + 1);
|
2011-05-24 07:08:58 +00:00
|
|
|
|
2011-09-05 16:04:15 +00:00
|
|
|
for (st = 1; st <= surface->substeps; st++) {
|
2012-05-12 16:11:34 +00:00
|
|
|
float subframe = ((float) st) / (surface->substeps + 1);
|
2011-06-16 10:41:00 +00:00
|
|
|
if (!dynamicPaint_doStep(scene, cObject, surface, timescale, subframe)) return 0;
|
2011-05-24 07:08:58 +00:00
|
|
|
}
|
|
|
|
}
|
2011-06-16 10:41:00 +00:00
|
|
|
|
2011-08-03 18:31:48 +00:00
|
|
|
return dynamicPaint_doStep(scene, cObject, surface, timescale, 0.0f);
|
2011-11-10 17:43:37 +00:00
|
|
|
}
|