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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Montagne <montagne29@wanadoo.fr>2016-05-24 17:48:10 +0300
committerBastien Montagne <montagne29@wanadoo.fr>2016-05-24 17:48:10 +0300
commitfaec4309147988fbab7b7d7ec661f5130358d169 (patch)
tree0c839f8f88fe80f4a3762980adb5efe729ce1b44 /source/blender/blenkernel
parentf85745b17bfe68673bf5f799e98c617d9471ddf1 (diff)
parente1dd83b399d46d81ea51f6c41725eec5c1a1db7a (diff)
Merge branch 'master' into blender2.8
Conflicts: intern/cycles/blender/blender_curves.cpp source/blender/blenkernel/intern/dynamicpaint.c source/blender/blenkernel/intern/particle.c source/blender/blenloader/intern/versioning_270.c source/blender/editors/physics/particle_edit.c source/blender/editors/transform/transform_snap_object.c source/blender/editors/util/undo.c source/blender/makesrna/intern/rna_object_force.c
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h2
-rw-r--r--source/blender/blenkernel/BKE_action.h11
-rw-r--r--source/blender/blenkernel/BKE_armature.h1
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_bvhutils.h77
-rw-r--r--source/blender/blenkernel/BKE_cloth.h2
-rw-r--r--source/blender/blenkernel/BKE_customdata.h4
-rw-r--r--source/blender/blenkernel/BKE_dynamicpaint.h2
-rw-r--r--source/blender/blenkernel/BKE_library.h3
-rw-r--r--source/blender/blenkernel/BKE_mesh_mapping.h5
-rw-r--r--source/blender/blenkernel/BKE_modifier.h3
-rw-r--r--source/blender/blenkernel/BKE_node.h4
-rw-r--r--source/blender/blenkernel/BKE_sketch.h1
-rw-r--r--source/blender/blenkernel/BKE_unit.h10
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c93
-rw-r--r--source/blender/blenkernel/intern/action.c131
-rw-r--r--source/blender/blenkernel/intern/armature.c220
-rw-r--r--source/blender/blenkernel/intern/armature_update.c14
-rw-r--r--source/blender/blenkernel/intern/blendfile.c3
-rw-r--r--source/blender/blenkernel/intern/bvhutils.c702
-rw-r--r--source/blender/blenkernel/intern/camera.c4
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c21
-rw-r--r--source/blender/blenkernel/intern/cloth.c124
-rw-r--r--source/blender/blenkernel/intern/collision.c10
-rw-r--r--source/blender/blenkernel/intern/constraint.c77
-rw-r--r--source/blender/blenkernel/intern/curve.c20
-rw-r--r--source/blender/blenkernel/intern/customdata.c54
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c4505
-rw-r--r--source/blender/blenkernel/intern/editmesh_bvh.c2
-rw-r--r--source/blender/blenkernel/intern/effect.c12
-rw-r--r--source/blender/blenkernel/intern/gpencil.c10
-rw-r--r--source/blender/blenkernel/intern/image.c37
-rw-r--r--source/blender/blenkernel/intern/image_gen.c261
-rw-r--r--source/blender/blenkernel/intern/lattice.c1
-rw-r--r--source/blender/blenkernel/intern/library.c13
-rw-r--r--source/blender/blenkernel/intern/mesh_mapping.c45
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c4
-rw-r--r--source/blender/blenkernel/intern/object.c5
-rw-r--r--source/blender/blenkernel/intern/pbvh.c11
-rw-r--r--source/blender/blenkernel/intern/scene.c9
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c2
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c91
-rw-r--r--source/blender/blenkernel/intern/sketch.c2
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c23
-rw-r--r--source/blender/blenkernel/intern/unit.c83
45 files changed, 3984 insertions, 2732 deletions
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index 7419b182c04..2b13a847e14 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -181,7 +181,7 @@ struct DerivedMesh {
int numVertData, numEdgeData, numTessFaceData, numLoopData, numPolyData;
int needsFree; /* checked on ->release, is set to 0 for cached results */
int deformedOnly; /* set by modifier stack if only deformed from original */
- BVHCache bvhCache;
+ BVHCache *bvhCache;
struct GPUDrawObject *drawObject;
DerivedMeshType type;
float auto_bump_scale;
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index 3fceef5d95d..cb282b46bec 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -79,12 +79,15 @@ typedef enum eAction_TransformFlags {
ACT_TRANS_ROT = (1 << 1),
/* scaling */
ACT_TRANS_SCALE = (1 << 2),
-
+
+ /* bbone shape - for all the parameters, provided one is set */
+ ACT_TRANS_BBONE = (1 << 3),
+
/* strictly not a transform, but custom properties are also
* quite often used in modern rigs
*/
- ACT_TRANS_PROP = (1 << 3),
-
+ ACT_TRANS_PROP = (1 << 4),
+
/* all flags */
ACT_TRANS_ONLY = (ACT_TRANS_LOC | ACT_TRANS_ROT | ACT_TRANS_SCALE),
ACT_TRANS_ALL = (ACT_TRANS_ONLY | ACT_TRANS_PROP)
@@ -144,6 +147,8 @@ void BKE_pose_channels_remove(
struct Object *ob,
bool (*filter_fn)(const char *bone_name, void *user_data), void *user_data);
+void BKE_pose_free_data_ex(struct bPose *pose, bool do_id_user);
+void BKE_pose_free_data(struct bPose *pose);
void BKE_pose_free(struct bPose *pose);
void BKE_pose_free_ex(struct bPose *pose, bool do_id_user);
void BKE_pose_copy_data(struct bPose **dst, struct bPose *src, const bool copy_constraints);
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index 6d00110e318..cc082c084ce 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -135,6 +135,7 @@ typedef struct Mat4 {
float mat[4][4];
} Mat4;
+void equalize_bbone_bezier(float *data, int desired);
void b_bone_spline_setup(struct bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BBONE_SUBDIV]);
/* like EBONE_VISIBLE */
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 5e7fdb91645..618b36c5851 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -28,7 +28,7 @@
* and keep comment above the defines.
* Use STRINGIFY() rather than defining with quotes */
#define BLENDER_VERSION 277
-#define BLENDER_SUBVERSION 0
+#define BLENDER_SUBVERSION 1
/* Several breakages with 270, e.g. constraint deg vs rad */
#define BLENDER_MINVERSION 270
#define BLENDER_MINSUBVERSION 6
diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h
index 08c0fcc0f3c..7bd3ca88076 100644
--- a/source/blender/blenkernel/BKE_bvhutils.h
+++ b/source/blender/blenkernel/BKE_bvhutils.h
@@ -39,10 +39,30 @@
*/
struct DerivedMesh;
+struct BMEditMesh;
struct MVert;
struct MFace;
/**
+* struct that kepts basic information about a BVHTree build from a editmesh
+*/
+typedef struct BVHTreeFromEditMesh {
+ struct BVHTree *tree;
+
+ /* default callbacks to bvh nearest and raycast */
+ BVHTree_NearestPointCallback nearest_callback;
+ BVHTree_RayCastCallback raycast_callback;
+ BVHTree_NearestToRayCallback nearest_to_ray_callback;
+
+ /* radius for raycast */
+ float sphere_radius;
+
+ /* Private data */
+ struct BMEditMesh *em;
+
+} BVHTreeFromEditMesh;
+
+/**
* struct that kepts basic information about a BVHTree build from a mesh
*/
typedef struct BVHTreeFromMesh {
@@ -69,8 +89,6 @@ typedef struct BVHTreeFromMesh {
float sphere_radius;
/* Private data */
- void *em_evil;
- bool em_evil_all; /* ignore selection/hidden state, adding all loops to the tree */
bool cached;
} BVHTreeFromMesh;
@@ -85,11 +103,19 @@ typedef struct BVHTreeFromMesh {
*
* free_bvhtree_from_mesh should be called when the tree is no longer needed.
*/
+BVHTree *bvhtree_from_editmesh_verts(
+ BVHTreeFromEditMesh *data, struct BMEditMesh *em,
+ float epsilon, int tree_type, int axis);
+BVHTree *bvhtree_from_editmesh_verts_ex(
+ BVHTreeFromEditMesh *data, struct BMEditMesh *em,
+ const BLI_bitmap *mask, int verts_num_active,
+ float epsilon, int tree_type, int axis);
+
BVHTree *bvhtree_from_mesh_verts(
struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis);
BVHTree *bvhtree_from_mesh_verts_ex(
struct BVHTreeFromMesh *data, struct MVert *vert, const int numVerts,
- const bool vert_allocated, BLI_bitmap *mask, int numVerts_active,
+ const bool vert_allocated, const BLI_bitmap *mask, int verts_num_active,
float epsilon, int tree_type, int axis);
BVHTree *bvhtree_from_mesh_edges(
@@ -103,7 +129,15 @@ BVHTree *bvhtree_from_mesh_faces_ex(
struct BVHTreeFromMesh *data,
struct MVert *vert, const bool vert_allocated,
struct MFace *face, const int numFaces, const bool face_allocated,
- BLI_bitmap *mask, int numFaces_active,
+ const BLI_bitmap *mask, int numFaces_active,
+ float epsilon, int tree_type, int axis);
+
+BVHTree *bvhtree_from_editmesh_looptri(
+ BVHTreeFromEditMesh *data, struct BMEditMesh *em, float epsilon,
+ int tree_type, int axis);
+BVHTree *bvhtree_from_editmesh_looptri_ex(
+ BVHTreeFromEditMesh *data, struct BMEditMesh *em,
+ const BLI_bitmap *mask, int looptri_num_active,
float epsilon, int tree_type, int axis);
BVHTree *bvhtree_from_mesh_looptri(
@@ -113,12 +147,13 @@ BVHTree *bvhtree_from_mesh_looptri_ex(
const struct MVert *vert, const bool vert_allocated,
const struct MLoop *mloop, const bool loop_allocated,
const struct MLoopTri *looptri, const int looptri_num, const bool looptri_allocated,
- BLI_bitmap *mask, int looptri_num_active,
+ const BLI_bitmap *mask, int looptri_num_active,
float epsilon, int tree_type, int axis);
/**
* Frees data allocated by a call to bvhtree_from_mesh_*.
*/
+void free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh *data);
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data);
/**
@@ -144,36 +179,14 @@ enum {
BVHTREE_FROM_EDGES = 1,
BVHTREE_FROM_FACES = 2,
BVHTREE_FROM_LOOPTRI = 3,
- /* all faces */
- BVHTREE_FROM_FACES_EDITMESH_ALL = 4,
- /* visible unselected, only used for transform snapping */
- BVHTREE_FROM_FACES_EDITMESH_SNAP = 5,
- // BVHTREE_FROM_EDGES_EDITMESH_SNAP = 6,
- BVHTREE_FROM_VERTS_EDITMESH_SNAP = 7,
};
-typedef struct LinkNode *BVHCache;
+typedef struct LinkNode BVHCache;
-
-/**
- * Queries a bvhcache for the cache bvhtree of the request type
- */
BVHTree *bvhcache_find(BVHCache *cache, int type);
-
-/**
- * Inserts a BVHTree of the given type under the cache
- * After that the caller no longer needs to worry when to free the BVHTree
- * as that will be done when the cache is freed.
- *
- * A call to this assumes that there was no previous cached tree of the given type
- */
-void bvhcache_insert(BVHCache *cache, BVHTree *tree, int type);
-
-/**
- * inits and frees a bvhcache
- */
-void bvhcache_init(BVHCache *cache);
-void bvhcache_free(BVHCache *cache);
+bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree);
+void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type);
+void bvhcache_init(BVHCache **cache_p);
+void bvhcache_free(BVHCache **cache_p);
#endif
-
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h
index 38ee690b857..ddc9fa530de 100644
--- a/source/blender/blenkernel/BKE_cloth.h
+++ b/source/blender/blenkernel/BKE_cloth.h
@@ -115,7 +115,7 @@ typedef struct ClothVertex {
float mass; /* mass / weight of the vertex */
float goal; /* goal, from SB */
float impulse[3]; /* used in collision.c */
- float *xrest; /* temporary valid for building springs */
+ float xrest[3]; /* rest position of the vertex */
unsigned int impulse_count; /* same as above */
float avg_spring_len; /* average length of connected springs */
float struct_stiff;
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 17ad51a7a16..2cdda34b9b5 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -244,7 +244,7 @@ void CustomData_free_elem(struct CustomData *data, int index, int count);
*/
void CustomData_interp(
const struct CustomData *source, struct CustomData *dest,
- int *src_indices, float *weights, float *sub_weights,
+ const int *src_indices, const float *weights, const float *sub_weights,
int count, int dest_index);
void CustomData_bmesh_interp_n(
struct CustomData *data, const void **src_blocks, const float *weights,
@@ -358,7 +358,7 @@ void CustomData_file_write_prepare(
struct CustomDataLayer **r_write_layers, struct CustomDataLayer *write_layers_buff, size_t write_layers_size);
/* query info over types */
-void CustomData_file_write_info(int type, const char **structname, int *structnum);
+void CustomData_file_write_info(int type, const char **r_struct_name, int *r_struct_num);
int CustomData_sizeof(int type);
/* get the name of a layer type */
diff --git a/source/blender/blenkernel/BKE_dynamicpaint.h b/source/blender/blenkernel/BKE_dynamicpaint.h
index 142ef1893ce..c552a618cd8 100644
--- a/source/blender/blenkernel/BKE_dynamicpaint.h
+++ b/source/blender/blenkernel/BKE_dynamicpaint.h
@@ -81,7 +81,7 @@ void dynamicPaint_resetPreview(struct DynamicPaintCanvasSettings *canvas);
struct DynamicPaintSurface *get_activeSurface(struct DynamicPaintCanvasSettings *canvas);
/* image sequence baking */
-int dynamicPaint_createUVSurface(struct Scene *scene, struct DynamicPaintSurface *surface);
+int dynamicPaint_createUVSurface(struct Scene *scene, struct DynamicPaintSurface *surface, float *progress, short *do_update);
int dynamicPaint_calculateFrame(struct DynamicPaintSurface *surface, struct Scene *scene, struct Object *cObject, int frame);
void dynamicPaint_outputSurfaceImage(struct DynamicPaintSurface *surface, char *filename, short output_layer);
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index c7b49e00da8..727818383b1 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -119,7 +119,8 @@ void BKE_main_lib_objects_recalc_all(struct Main *bmain);
/* (MAX_ID_NAME - 2) + 3 */
void BKE_id_ui_prefix(char name[66 + 1], const struct ID *id);
-void BKE_library_make_local(struct Main *bmain, struct Library *lib, bool untagged_only, bool set_fake);
+void BKE_library_make_local(
+ struct Main *bmain, const struct Library *lib, const bool untagged_only, const bool set_fake);
typedef void (*BKE_library_free_window_manager_cb)(struct bContext *, struct wmWindowManager *);
typedef void (*BKE_library_free_notifier_reference_cb)(const void *);
diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h
index d7dd9ed3ac5..dff79b6cc22 100644
--- a/source/blender/blenkernel/BKE_mesh_mapping.h
+++ b/source/blender/blenkernel/BKE_mesh_mapping.h
@@ -114,6 +114,11 @@ void BKE_mesh_vert_loop_map_create(
MeshElemMap **r_map, int **r_mem,
const struct MPoly *mface, const struct MLoop *mloop,
int totvert, int totface, int totloop);
+void BKE_mesh_vert_looptri_map_create(
+ MeshElemMap **r_map, int **r_mem,
+ const struct MVert *mvert, const int totvert,
+ const struct MLoopTri *mlooptri, const int totlooptri,
+ const struct MLoop *mloop, const int totloop);
void BKE_mesh_vert_edge_map_create(
MeshElemMap **r_map, int **r_mem,
const struct MEdge *medge, int totvert, int totedge);
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index c6f8befe964..ab0b120faf3 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -101,7 +101,8 @@ typedef enum {
eModifierTypeFlag_NoUserAdd = (1 << 8),
/* For modifiers that use CD_PREVIEW_MCOL for preview. */
- eModifierTypeFlag_UsesPreview = (1 << 9)
+ eModifierTypeFlag_UsesPreview = (1 << 9),
+ eModifierTypeFlag_AcceptsLattice = (1 << 10),
} ModifierTypeFlag;
/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 2ece0f7a028..76e49566d19 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -642,12 +642,12 @@ void BKE_node_tree_unlink_id(ID *id, struct bNodeTree *ntree);
* Examples:
*
* \code{.c}
- * FOREACH_NODETREE(bmain, nodetree) {
+ * FOREACH_NODETREE(bmain, nodetree, id) {
* if (id == nodetree)
* printf("This is a linkable node tree");
* } FOREACH_NODETREE_END
*
- * FOREACH_NODETREE(bmain, nodetree) {
+ * FOREACH_NODETREE(bmain, nodetree, id) {
* if (nodetree->idname == "ShaderNodeTree")
* printf("This is a shader node tree);
* if (GS(id) == ID_MA)
diff --git a/source/blender/blenkernel/BKE_sketch.h b/source/blender/blenkernel/BKE_sketch.h
index c4cfcba4b35..9b9c125fbe6 100644
--- a/source/blender/blenkernel/BKE_sketch.h
+++ b/source/blender/blenkernel/BKE_sketch.h
@@ -82,7 +82,6 @@ typedef struct SK_Intersection {
typedef struct SK_Sketch {
ListBase strokes;
- ListBase depth_peels;
SK_Stroke *active_stroke;
SK_Stroke *gesture;
SK_Point next_point;
diff --git a/source/blender/blenkernel/BKE_unit.h b/source/blender/blenkernel/BKE_unit.h
index b351bc6fe3e..278b303a315 100644
--- a/source/blender/blenkernel/BKE_unit.h
+++ b/source/blender/blenkernel/BKE_unit.h
@@ -54,11 +54,11 @@ bool bUnit_IsValid(int system, int type);
/* loop over scales, coudl add names later */
//double bUnit_Iter(void **unit, char **name, int system, int type);
-void bUnit_GetSystem(void **usys_pt, int *len, int system, int type);
-int bUnit_GetBaseUnit(void *usys_pt);
-const char *bUnit_GetName(void *usys_pt, int index);
-const char *bUnit_GetNameDisplay(void *usys_pt, int index);
-double bUnit_GetScaler(void *usys_pt, int index);
+void bUnit_GetSystem(int system, int type, void const **r_usys_pt, int *r_len);
+int bUnit_GetBaseUnit(const void *usys_pt);
+const char *bUnit_GetName(const void *usys_pt, int index);
+const char *bUnit_GetNameDisplay(const void *usys_pt, int index);
+double bUnit_GetScaler(const void *usys_pt, int index);
/* aligned with PropertyUnit */
enum {
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index a32fd99aa04..bcc3b60b34e 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -647,13 +647,15 @@ void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate)
void DM_update_materials(DerivedMesh *dm, Object *ob)
{
int i, totmat = ob->totcol + 1; /* materials start from 1, default material is 0 */
- dm->totmat = totmat;
- /* invalidate old materials */
- if (dm->mat)
- MEM_freeN(dm->mat);
+ if (dm->totmat != totmat) {
+ dm->totmat = totmat;
+ /* invalidate old materials */
+ if (dm->mat)
+ MEM_freeN(dm->mat);
- dm->mat = MEM_callocN(totmat * sizeof(*dm->mat), "DerivedMesh.mat");
+ dm->mat = MEM_mallocN(totmat * sizeof(*dm->mat), "DerivedMesh.mat");
+ }
/* we leave last material as empty - rationale here is being able to index
* the materials by using the mf->mat_nr directly and leaving the last
@@ -661,6 +663,7 @@ void DM_update_materials(DerivedMesh *dm, Object *ob)
for (i = 0; i < totmat - 1; i++) {
dm->mat[i] = give_current_material(ob, i + 1);
}
+ dm->mat[i] = NULL;
}
MLoopUV *DM_paint_uvlayer_active_get(DerivedMesh *dm, int mat_nr)
@@ -3626,12 +3629,41 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
dm->calcLoopTangents(dm, false, (const char (*)[MAX_NAME])tangent_names, tangent_names_count);
for (b = 0; b < gattribs->totlayer; b++) {
- if (gattribs->layer[b].type == CD_MTFACE) {
+ int type = gattribs->layer[b].type;
+ layer = -1;
+ if (type == CD_AUTO_FROM_NAME) {
+ /* We need to deduct what exact layer is used.
+ *
+ * We do it based on the specified name.
+ */
+ if (gattribs->layer[b].name[0]) {
+ layer = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, gattribs->layer[b].name);
+ type = CD_TANGENT;
+ if (layer == -1) {
+ layer = CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, gattribs->layer[b].name);
+ type = CD_MCOL;
+ }
+ if (layer == -1) {
+ layer = CustomData_get_named_layer_index(ldata, CD_MLOOPUV, gattribs->layer[b].name);
+ type = CD_MTFACE;
+ }
+ if (layer == -1) {
+ continue;
+ }
+ }
+ else {
+ /* Fall back to the UV layer, which matches old behavior. */
+ type = CD_MTFACE;
+ }
+ }
+ if (type == CD_MTFACE) {
/* uv coordinates */
- if (gattribs->layer[b].name[0])
- layer = CustomData_get_named_layer_index(ldata, CD_MLOOPUV, gattribs->layer[b].name);
- else
- layer = CustomData_get_active_layer_index(ldata, CD_MLOOPUV);
+ if (layer == -1) {
+ if (gattribs->layer[b].name[0])
+ layer = CustomData_get_named_layer_index(ldata, CD_MLOOPUV, gattribs->layer[b].name);
+ else
+ layer = CustomData_get_active_layer_index(ldata, CD_MLOOPUV);
+ }
a = attribs->tottface++;
@@ -3647,11 +3679,13 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
attribs->tface[a].gl_index = gattribs->layer[b].glindex;
attribs->tface[a].gl_texco = gattribs->layer[b].gltexco;
}
- else if (gattribs->layer[b].type == CD_MCOL) {
- if (gattribs->layer[b].name[0])
- layer = CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, gattribs->layer[b].name);
- else
- layer = CustomData_get_active_layer_index(ldata, CD_MLOOPCOL);
+ else if (type == CD_MCOL) {
+ if (layer == -1) {
+ if (gattribs->layer[b].name[0])
+ layer = CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, gattribs->layer[b].name);
+ else
+ layer = CustomData_get_active_layer_index(ldata, CD_MLOOPCOL);
+ }
a = attribs->totmcol++;
@@ -3667,13 +3701,14 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
attribs->mcol[a].gl_index = gattribs->layer[b].glindex;
}
- else if (gattribs->layer[b].type == CD_TANGENT) {
+ else if (type == CD_TANGENT) {
/* note, even with 'is_editmesh' this uses the derived-meshes loop data */
-
- if (gattribs->layer[b].name[0])
- layer = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, gattribs->layer[b].name);
- else
- layer = CustomData_get_active_layer_index(&dm->loopData, CD_TANGENT);
+ if (layer == -1) {
+ if (gattribs->layer[b].name[0])
+ layer = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, gattribs->layer[b].name);
+ else
+ layer = CustomData_get_active_layer_index(&dm->loopData, CD_TANGENT);
+ }
a = attribs->tottang++;
@@ -3688,9 +3723,11 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
attribs->tang[a].gl_index = gattribs->layer[b].glindex;
}
- else if (gattribs->layer[b].type == CD_ORCO) {
+ else if (type == CD_ORCO) {
/* original coordinates */
- layer = CustomData_get_layer_index(vdata, CD_ORCO);
+ if (layer == -1) {
+ layer = CustomData_get_layer_index(vdata, CD_ORCO);
+ }
attribs->totorco = 1;
if (layer != -1) {
@@ -3754,17 +3791,17 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
/* vertex colors */
for (b = 0; b < attribs->totmcol; b++) {
- GLubyte col[4];
+ GLfloat col[4];
if (attribs->mcol[b].array) {
const MLoopCol *cp = &attribs->mcol[b].array[loop];
- copy_v4_v4_uchar(col, &cp->r);
+ rgba_uchar_to_float(col, &cp->r);
}
else {
- col[0] = 0; col[1] = 0; col[2] = 0; col[3] = 0;
+ zero_v4(col);
}
- glVertexAttrib4ubv(attribs->mcol[b].gl_index, col);
+ glVertexAttrib4fv(attribs->mcol[b].gl_index, col);
}
/* tangent for normal mapping */
@@ -3996,7 +4033,7 @@ void DM_init_origspace(DerivedMesh *dm)
float p_nor[3], co[3];
float mat[3][3];
- float min[2] = {FLT_MAX, FLT_MAX}, max[2] = {FLT_MIN, FLT_MIN};
+ float min[2] = {FLT_MAX, FLT_MAX}, max[2] = {-FLT_MAX, -FLT_MAX};
float translate[2], scale[2];
BKE_mesh_calc_poly_normal(mp, l, mv, p_nor);
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 5b1bb8cb2bb..df9b9683687 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -493,6 +493,8 @@ bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name)
unit_axis_angle(chan->rotAxis, &chan->rotAngle);
chan->size[0] = chan->size[1] = chan->size[2] = 1.0f;
+ chan->scaleIn = chan->scaleOut = 1.0f;
+
chan->limitmin[0] = chan->limitmin[1] = chan->limitmin[2] = -180.0f;
chan->limitmax[0] = chan->limitmax[1] = chan->limitmax[2] = 180.0f;
chan->stiffness[0] = chan->stiffness[1] = chan->stiffness[2] = 0.0f;
@@ -596,7 +598,16 @@ void BKE_pose_copy_data(bPose **dst, bPose *src, const bool copy_constraints)
outPose = MEM_callocN(sizeof(bPose), "pose");
BLI_duplicatelist(&outPose->chanbase, &src->chanbase);
-
+
+ /* Rebuild ghash here too, so that name lookups below won't be too bad...
+ * BUT this will have the penalty that the ghash will be built twice
+ * if BKE_pose_rebuild() gets called after this...
+ */
+ if (outPose->chanbase.first != outPose->chanbase.last) {
+ outPose->chanhash = NULL;
+ BKE_pose_channels_hash_make(outPose);
+ }
+
outPose->iksolver = src->iksolver;
outPose->ikdata = NULL;
outPose->ikparam = MEM_dupallocN(src->ikparam);
@@ -608,10 +619,16 @@ void BKE_pose_copy_data(bPose **dst, bPose *src, const bool copy_constraints)
id_us_plus(&pchan->custom->id);
}
- /* warning, O(n2) here, but it's a rarely used feature. */
+ /* warning, O(n2) here, if done without the hash, but these are rarely used features. */
if (pchan->custom_tx) {
pchan->custom_tx = BKE_pose_channel_find_name(outPose, pchan->custom_tx->name);
}
+ if (pchan->bbone_prev) {
+ pchan->bbone_prev = BKE_pose_channel_find_name(outPose, pchan->bbone_prev->name);
+ }
+ if (pchan->bbone_next) {
+ pchan->bbone_next = BKE_pose_channel_find_name(outPose, pchan->bbone_next->name);
+ }
if (copy_constraints) {
BKE_constraints_copy(&listb, &pchan->constraints, true); // BKE_constraints_copy NULLs listb
@@ -726,7 +743,7 @@ void BKE_pose_channels_remove(
Object *ob,
bool (*filter_fn)(const char *bone_name, void *user_data), void *user_data)
{
- /* First erase any associated pose channel */
+ /* Erase any associated pose channel, along with any references to them */
if (ob->pose) {
bPoseChannel *pchan, *pchan_next;
bConstraint *con;
@@ -735,6 +752,7 @@ void BKE_pose_channels_remove(
pchan_next = pchan->next;
if (filter_fn(pchan->name, user_data)) {
+ /* Bone itself is being removed */
BKE_pose_channel_free(pchan);
if (ob->pose->chanhash) {
BLI_ghash_remove(ob->pose->chanhash, pchan->name, NULL, NULL);
@@ -742,6 +760,7 @@ void BKE_pose_channels_remove(
BLI_freelinkN(&ob->pose->chanbase, pchan);
}
else {
+ /* Maybe something the bone references is being removed instead? */
for (con = pchan->constraints.first; con; con = con->next) {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
@@ -765,6 +784,20 @@ void BKE_pose_channels_remove(
cti->flush_constraint_targets(con, &targets, 0);
}
}
+
+ if (pchan->bbone_prev) {
+ if (filter_fn(pchan->bbone_prev->name, user_data))
+ pchan->bbone_prev = NULL;
+ }
+ if (pchan->bbone_next) {
+ if (filter_fn(pchan->bbone_next->name, user_data))
+ pchan->bbone_next = NULL;
+ }
+
+ if (pchan->custom_tx) {
+ if (filter_fn(pchan->custom_tx->name, user_data))
+ pchan->custom_tx = NULL;
+ }
}
}
}
@@ -824,26 +857,35 @@ void BKE_pose_channels_free(bPose *pose)
BKE_pose_channels_free_ex(pose, true);
}
+void BKE_pose_free_data_ex(bPose *pose, bool do_id_user)
+{
+ /* free pose-channels */
+ BKE_pose_channels_free_ex(pose, do_id_user);
+
+ /* free pose-groups */
+ if (pose->agroups.first)
+ BLI_freelistN(&pose->agroups);
+
+ /* free IK solver state */
+ BIK_clear_data(pose);
+
+ /* free IK solver param */
+ if (pose->ikparam)
+ MEM_freeN(pose->ikparam);
+}
+
+void BKE_pose_free_data(bPose *pose)
+{
+ BKE_pose_free_data_ex(pose, true);
+}
+
/**
* Removes and deallocates all data from a pose, and also frees the pose.
*/
void BKE_pose_free_ex(bPose *pose, bool do_id_user)
{
if (pose) {
- /* free pose-channels */
- BKE_pose_channels_free_ex(pose, do_id_user);
-
- /* free pose-groups */
- if (pose->agroups.first)
- BLI_freelistN(&pose->agroups);
-
- /* free IK solver state */
- BIK_clear_data(pose);
-
- /* free IK solver param */
- if (pose->ikparam)
- MEM_freeN(pose->ikparam);
-
+ BKE_pose_free_data_ex(pose, do_id_user);
/* free pose */
MEM_freeN(pose);
}
@@ -869,6 +911,15 @@ static void copy_pose_channel_data(bPoseChannel *pchan, const bPoseChannel *chan
copy_m4_m4(pchan->pose_mat, (float(*)[4])chan->pose_mat);
pchan->flag = chan->flag;
+ pchan->roll1 = chan->roll1;
+ pchan->roll2 = chan->roll2;
+ pchan->curveInX = chan->curveInX;
+ pchan->curveInY = chan->curveInY;
+ pchan->curveOutX = chan->curveOutX;
+ pchan->curveOutY = chan->curveOutY;
+ pchan->scaleIn = chan->scaleIn;
+ pchan->scaleOut = chan->scaleOut;
+
con = chan->constraints.first;
for (pcon = pchan->constraints.first; pcon && con; pcon = pcon->next, con = con->next) {
pcon->enforce = con->enforce;
@@ -879,7 +930,7 @@ static void copy_pose_channel_data(bPoseChannel *pchan, const bPoseChannel *chan
/**
* Copy the internal members of each pose channel including constraints
* and ID-Props, used when duplicating bones in editmode.
- * (unlike copy_pose_channel_data which only).
+ * (unlike copy_pose_channel_data which only does posing-related stuff).
*
* \note use when copying bones in editmode (on returned value from #BKE_pose_channel_verify)
*/
@@ -902,6 +953,11 @@ void BKE_pose_channel_copy_data(bPoseChannel *pchan, const bPoseChannel *pchan_f
pchan->ikstretch = pchan_from->ikstretch;
pchan->ikrotweight = pchan_from->ikrotweight;
pchan->iklinweight = pchan_from->iklinweight;
+
+ /* bbone settings (typically not animated) */
+ pchan->bboneflag = pchan_from->bboneflag;
+ pchan->bbone_next = pchan_from->bbone_next;
+ pchan->bbone_prev = pchan_from->bbone_prev;
/* constraints */
BKE_constraints_copy(&pchan->constraints, &pchan_from->constraints, true);
@@ -1271,6 +1327,18 @@ short action_get_item_transforms(bAction *act, Object *ob, bPoseChannel *pchan,
}
}
+ if ((curves) || (flags & ACT_TRANS_BBONE) == 0) {
+ /* bbone shape properties */
+ pPtr = strstr(bPtr, "bbone_");
+ if (pPtr) {
+ flags |= ACT_TRANS_BBONE;
+
+ if (curves)
+ BLI_addtail(curves, BLI_genericNodeN(fcu));
+ continue;
+ }
+ }
+
if ((curves) || (flags & ACT_TRANS_PROP) == 0) {
/* custom properties only */
pPtr = strstr(bPtr, "[\""); /* extra '"' comment here to keep my texteditor functionlist working :) */
@@ -1330,8 +1398,13 @@ void BKE_pose_rest(bPose *pose)
unit_qt(pchan->quat);
unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
pchan->size[0] = pchan->size[1] = pchan->size[2] = 1.0f;
-
- pchan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE);
+
+ pchan->roll1 = pchan->roll2 = 0.0f;
+ pchan->curveInX = pchan->curveInY = 0.0f;
+ pchan->curveOutX = pchan->curveOutY = 0.0f;
+ pchan->scaleIn = pchan->scaleOut = 1.0f;
+
+ pchan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE | POSE_BBONE_SHAPE);
}
}
@@ -1366,9 +1439,19 @@ bool BKE_pose_copy_result(bPose *to, bPose *from)
copy_v3_v3(pchanto->pose_head, pchanfrom->pose_head);
copy_v3_v3(pchanto->pose_tail, pchanfrom->pose_tail);
+ pchanto->roll1 = pchanfrom->roll1;
+ pchanto->roll2 = pchanfrom->roll2;
+ pchanto->curveInX = pchanfrom->curveInX;
+ pchanto->curveInY = pchanfrom->curveInY;
+ pchanto->curveOutX = pchanfrom->curveOutX;
+ pchanto->curveOutY = pchanfrom->curveOutY;
+ pchanto->scaleIn = pchanfrom->scaleIn;
+ pchanto->scaleOut = pchanfrom->scaleOut;
+
pchanto->rotmode = pchanfrom->rotmode;
pchanto->flag = pchanfrom->flag;
pchanto->protectflag = pchanfrom->protectflag;
+ pchanto->bboneflag = pchanfrom->bboneflag;
}
}
return true;
@@ -1415,7 +1498,13 @@ void what_does_obaction(Object *ob, Object *workob, bPose *pose, bAction *act, c
workob->pose = pose; /* need to set pose too, since this is used for both types of Action Constraint */
if (pose) {
- BKE_pose_channels_hash_make(pose);
+ /* This function is most likely to be used with a temporary pose with a single bone in there.
+ * For such cases it makes no sense to create hash since it'll only waste CPU ticks on memory
+ * allocation and also will make lookup slower.
+ */
+ if (pose->chanbase.first != pose->chanbase.last) {
+ BKE_pose_channels_hash_make(pose);
+ }
if (pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
BKE_pose_update_constraint_flags(pose);
}
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 564c670fb3a..04b4733fd44 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -41,6 +41,7 @@
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_ghash.h"
+#include "BLI_task.h"
#include "BLI_utildefines.h"
#include "DNA_anim_types.h"
@@ -48,6 +49,7 @@
#include "DNA_constraint_types.h"
#include "DNA_mesh_types.h"
#include "DNA_lattice_types.h"
+#include "DNA_listBase.h"
#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
@@ -427,7 +429,7 @@ int bone_autoside_name(char name[MAXBONENAME], int UNUSED(strip_number), short a
/* ************* B-Bone support ******************* */
/* data has MAX_BBONE_SUBDIV+1 interpolated points, will become desired amount with equal distances */
-static void equalize_bezier(float *data, int desired)
+void equalize_bbone_bezier(float *data, int desired)
{
float *fp, totdist, ddist, dist, fac1, fac2;
float pdist[MAX_BBONE_SUBDIV + 1];
@@ -473,7 +475,7 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
{
bPoseChannel *next, *prev;
Bone *bone = pchan->bone;
- float h1[3], h2[3], scale[3], length, hlength1, hlength2, roll1 = 0.0f, roll2;
+ float h1[3], h2[3], scale[3], length, roll1 = 0.0f, roll2;
float mat3[3][3], imat[4][4], posemat[4][4], scalemat[4][4], iscalemat[4][4];
float data[MAX_BBONE_SUBDIV + 1][4], *fp;
int a;
@@ -494,16 +496,21 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
}
}
- hlength1 = bone->ease1 * length * 0.390464f; /* 0.5f * sqrt(2) * kappa, the handle length for near-perfect circles */
- hlength2 = bone->ease2 * length * 0.390464f;
-
- /* evaluate next and prev bones */
- if (bone->flag & BONE_CONNECTED)
- prev = pchan->parent;
- else
- prev = NULL;
+ /* get "next" and "prev" bones - these are used for handle calculations */
+ if (pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES) {
+ /* use the provided bones as the next/prev - leave blank to eliminate this effect altogether */
+ prev = pchan->bbone_prev;
+ next = pchan->bbone_next;
+ }
+ else {
+ /* evaluate next and prev bones */
+ if (bone->flag & BONE_CONNECTED)
+ prev = pchan->parent;
+ else
+ prev = NULL;
- next = pchan->child;
+ next = pchan->child;
+ }
/* find the handle points, since this is inside bone space, the
* first point = (0, 0, 0)
@@ -523,10 +530,27 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
float difmat[4][4], result[3][3], imat3[3][3];
/* transform previous point inside this bone space */
- if (rest)
- copy_v3_v3(h1, prev->bone->arm_head);
- else
- copy_v3_v3(h1, prev->pose_head);
+ if ((pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES) &&
+ (pchan->bboneflag & PCHAN_BBONE_CUSTOM_START_REL))
+ {
+ /* Use delta movement (from restpose), and apply this relative to the current bone's head */
+ if (rest) {
+ /* in restpose, arm_head == pose_head */
+ h1[0] = h1[1] = h1[2] = 0.0f;
+ }
+ else {
+ float delta[3];
+ sub_v3_v3v3(delta, prev->pose_head, prev->bone->arm_head);
+ sub_v3_v3v3(h1, pchan->pose_head, delta);
+ }
+ }
+ else {
+ /* Use bone head as absolute position */
+ if (rest)
+ copy_v3_v3(h1, prev->bone->arm_head);
+ else
+ copy_v3_v3(h1, prev->pose_head);
+ }
mul_m4_v3(imat, h1);
if (prev->bone->segments > 1) {
@@ -536,7 +560,7 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
}
normalize_v3(h1);
- mul_v3_fl(h1, -hlength1);
+ negate_v3(h1);
if (prev->bone->segments == 1) {
/* find the previous roll to interpolate */
@@ -555,17 +579,34 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
}
}
else {
- h1[0] = 0.0f; h1[1] = hlength1; h1[2] = 0.0f;
+ h1[0] = 0.0f; h1[1] = 1.0; h1[2] = 0.0f;
roll1 = 0.0f;
}
if (next) {
float difmat[4][4], result[3][3], imat3[3][3];
/* transform next point inside this bone space */
- if (rest)
- copy_v3_v3(h2, next->bone->arm_tail);
- else
- copy_v3_v3(h2, next->pose_tail);
+ if ((pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES) &&
+ (pchan->bboneflag & PCHAN_BBONE_CUSTOM_END_REL))
+ {
+ /* Use delta movement (from restpose), and apply this relative to the current bone's tail */
+ if (rest) {
+ /* in restpose, arm_tail == pose_tail */
+ h2[0] = h2[1] = h2[2] = 0.0f;
+ }
+ else {
+ float delta[3];
+ sub_v3_v3v3(delta, next->pose_tail, next->bone->arm_tail);
+ add_v3_v3v3(h2, pchan->pose_tail, delta);
+ }
+ }
+ else {
+ /* Use bone tail as absolute position */
+ if (rest)
+ copy_v3_v3(h2, next->bone->arm_tail);
+ else
+ copy_v3_v3(h2, next->pose_tail);
+ }
mul_m4_v3(imat, h2);
/* if next bone is B-bone too, use average handle direction */
@@ -591,14 +632,66 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
roll2 = atan2f(mat3[2][0], mat3[2][2]);
- /* and only now negate handle */
- mul_v3_fl(h2, -hlength2);
}
else {
- h2[0] = 0.0f; h2[1] = -hlength2; h2[2] = 0.0f;
+ h2[0] = 0.0f; h2[1] = 1.0f; h2[2] = 0.0f;
roll2 = 0.0;
}
+ {
+ const float circle_factor = length * (cubic_tangent_factor_circle_v3(h1, h2) / 0.75f);
+ const float hlength1 = bone->ease1 * circle_factor;
+ const float hlength2 = bone->ease2 * circle_factor;
+
+ /* and only now negate h2 */
+ mul_v3_fl(h1, hlength1);
+ mul_v3_fl(h2, -hlength2);
+ }
+
+ /* Add effects from bbone properties over the top
+ * - These properties allow users to hand-animate the
+ * bone curve/shape, without having to resort to using
+ * extra bones
+ * - The "bone" level offsets are for defining the restpose
+ * shape of the bone (e.g. for curved eyebrows for example).
+ * -> In the viewport, it's needed to define what the rest pose
+ * looks like
+ * -> For "rest == 0", we also still need to have it present
+ * so that we can "cancel out" this restpose when it comes
+ * time to deform some geometry, it won't cause double transforms.
+ * - The "pchan" level offsets are the ones that animators actually
+ * end up animating
+ */
+ {
+ /* add extra rolls */
+ roll1 += bone->roll1 + (!rest ? pchan->roll1 : 0.0f);
+ roll2 += bone->roll2 + (!rest ? pchan->roll2 : 0.0f);
+
+ if (bone->flag & BONE_ADD_PARENT_END_ROLL) {
+ if (prev) {
+ if (prev->bone)
+ roll1 += prev->bone->roll2;
+
+ if (!rest)
+ roll1 += prev->roll2;
+ }
+ }
+
+ /* extra curve x / y */
+ /* NOTE: Scale correction factors here are to compensate for some random floating-point glitches
+ * when scaling up the bone or it's parent by a factor of approximately 8.15/6, which results
+ * in the bone length getting scaled up too (from 1 to 8), causing the curve to flatten out.
+ */
+ const float xscale_correction = (do_scale) ? scale[0] : 1.0f;
+ const float yscale_correction = (do_scale) ? scale[2] : 1.0f;
+
+ h1[0] += (bone->curveInX + (!rest ? pchan->curveInX : 0.0f)) * xscale_correction;
+ h1[2] += (bone->curveInY + (!rest ? pchan->curveInY : 0.0f)) * yscale_correction;
+
+ h2[0] += (bone->curveOutX + (!rest ? pchan->curveOutX : 0.0f)) * xscale_correction;
+ h2[2] += (bone->curveOutY + (!rest ? pchan->curveOutY : 0.0f)) * yscale_correction;
+ }
+
/* make curve */
if (bone->segments > MAX_BBONE_SUBDIV)
bone->segments = MAX_BBONE_SUBDIV;
@@ -608,20 +701,45 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
BKE_curve_forward_diff_bezier(0.0f, h1[2], h2[2], 0.0f, data[0] + 2, MAX_BBONE_SUBDIV, 4 * sizeof(float));
BKE_curve_forward_diff_bezier(roll1, roll1 + 0.390464f * (roll2 - roll1), roll2 - 0.390464f * (roll2 - roll1), roll2, data[0] + 3, MAX_BBONE_SUBDIV, 4 * sizeof(float));
- equalize_bezier(data[0], bone->segments); /* note: does stride 4! */
+ equalize_bbone_bezier(data[0], bone->segments); /* note: does stride 4! */
/* make transformation matrices for the segments for drawing */
for (a = 0, fp = data[0]; a < bone->segments; a++, fp += 4) {
sub_v3_v3v3(h1, fp + 4, fp);
vec_roll_to_mat3(h1, fp[3], mat3); /* fp[3] is roll */
-
+
copy_m4_m3(result_array[a].mat, mat3);
copy_v3_v3(result_array[a].mat[3], fp);
-
+
if (do_scale) {
/* correct for scaling when this matrix is used in scaled space */
mul_m4_series(result_array[a].mat, iscalemat, result_array[a].mat, scalemat);
}
+
+ /* BBone scale... */
+ {
+ const int num_segments = bone->segments;
+
+ const float scaleIn = bone->scaleIn * (!rest ? pchan->scaleIn : 1.0f);
+ const float scaleFactorIn = 1.0f + (scaleIn - 1.0f) * ((float)(num_segments - a) / (float)num_segments);
+
+ const float scaleOut = bone->scaleOut * (!rest ? pchan->scaleOut : 1.0f);
+ const float scaleFactorOut = 1.0f + (scaleOut - 1.0f) * ((float)(a + 1) / (float)num_segments);
+
+ const float scalefac = scaleFactorIn * scaleFactorOut;
+ float bscalemat[4][4], bscale[3];
+
+ bscale[0] = scalefac;
+ bscale[1] = 1.0f;
+ bscale[2] = scalefac;
+
+ size_to_mat4(bscalemat, bscale);
+
+ /* Note: don't multiply by inverse scale mat here, as it causes problems with scaling shearing and breaking segment chains */
+ /*mul_m4_series(result_array[a].mat, ibscalemat, result_array[a].mat, bscalemat);*/
+ mul_m4_series(result_array[a].mat, result_array[a].mat, bscalemat);
+ }
+
}
}
@@ -667,7 +785,6 @@ static void pchan_b_bone_defmats(bPoseChannel *pchan, bPoseChanDeform *pdef_info
float tmat[4][4];
invert_m4_m4(tmat, b_bone_rest[a].mat);
-
mul_m4_series(b_bone_mats[a + 1].mat, pchan->chan_mat, bone->arm_mat, b_bone[a].mat, tmat, b_bone_mats[0].mat);
if (use_quaternion)
@@ -681,10 +798,10 @@ static void b_bone_deform(bPoseChanDeform *pdef_info, Bone *bone, float co[3], D
float (*mat)[4] = b_bone[0].mat;
float segment, y;
int a;
-
+
/* need to transform co back to bonespace, only need y */
y = mat[0][1] * co[0] + mat[1][1] * co[1] + mat[2][1] * co[2] + mat[3][1];
-
+
/* now calculate which of the b_bones are deforming this */
segment = bone->length / ((float)bone->segments);
a = (int)(y / segment);
@@ -854,6 +971,32 @@ static void pchan_bone_deform(bPoseChannel *pchan, bPoseChanDeform *pdef_info, f
(*contrib) += weight;
}
+typedef struct ArmatureBBoneDefmatsData {
+ bPoseChanDeform *pdef_info_array;
+ DualQuat *dualquats;
+ bool use_quaternion;
+} ArmatureBBoneDefmatsData;
+
+static void armature_bbone_defmats_cb(void *userdata, Link *iter, int index)
+{
+ ArmatureBBoneDefmatsData *data = userdata;
+ bPoseChannel *pchan = (bPoseChannel *)iter;
+
+ if (!(pchan->bone->flag & BONE_NO_DEFORM)) {
+ bPoseChanDeform *pdef_info = &data->pdef_info_array[index];
+ const bool use_quaternion = data->use_quaternion;
+
+ if (pchan->bone->segments > 1) {
+ pchan_b_bone_defmats(pchan, pdef_info, use_quaternion);
+ }
+
+ if (use_quaternion) {
+ pdef_info->dual_quat = &data->dualquats[index];
+ mat4_to_dquat(pdef_info->dual_quat, pchan->bone->arm_mat, pchan->chan_mat);
+ }
+ }
+}
+
void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3],
float (*defMats)[3][3], int numVerts, int deformflag,
float (*prevCos)[3], const char *defgrp_name)
@@ -897,19 +1040,10 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
pdef_info_array = MEM_callocN(sizeof(bPoseChanDeform) * totchan, "bPoseChanDeform");
- totchan = 0;
- pdef_info = pdef_info_array;
- for (pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next, pdef_info++) {
- if (!(pchan->bone->flag & BONE_NO_DEFORM)) {
- if (pchan->bone->segments > 1)
- pchan_b_bone_defmats(pchan, pdef_info, use_quaternion);
-
- if (use_quaternion) {
- pdef_info->dual_quat = &dualquats[totchan++];
- mat4_to_dquat(pdef_info->dual_quat, pchan->bone->arm_mat, pchan->chan_mat);
- }
- }
- }
+ ArmatureBBoneDefmatsData data = {
+ .pdef_info_array = pdef_info_array, .dualquats = dualquats, .use_quaternion = use_quaternion
+ };
+ BLI_task_parallel_listbase(&armOb->pose->chanbase, &data, armature_bbone_defmats_cb, totchan > 512);
/* get the def_nr for the overall armature vertex group if present */
armature_def_nr = defgroup_name_index(target, defgrp_name);
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index ceda9f056bb..826bb12a912 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -619,7 +619,9 @@ void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx),
else {
/* TODO(sergey): Use time source node for time. */
float ctime = BKE_scene_frame_get(scene); /* not accurate... */
- BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+ if ((pchan->flag & POSE_DONE) == 0) {
+ BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+ }
}
}
}
@@ -631,12 +633,18 @@ void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx),
{
Scene *scene = G.main->scene.first;
DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name);
- if (pchan->flag & POSE_IKTREE || pchan->flag & POSE_IKSPLINE) {
+ bArmature *arm = (bArmature *)ob->data;
+ if (arm->flag & ARM_RESTPOS) {
+ return;
+ }
+ else if (pchan->flag & POSE_IKTREE || pchan->flag & POSE_IKSPLINE) {
/* IK are being solved separately/ */
}
else {
float ctime = BKE_scene_frame_get(scene); /* not accurate... */
- BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+ if ((pchan->flag & POSE_DONE) == 0) {
+ BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+ }
}
}
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index 4605a12f9a0..bedf262541f 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -492,6 +492,9 @@ static void blendfile_write_partial_cb(void *UNUSED(handle), Main *UNUSED(bmain)
/* only tag for need-expand if not done, prevents eternal loops */
if ((id->tag & LIB_TAG_DOIT) == 0)
id->tag |= LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT;
+
+ if (id->lib && (id->lib->id.tag & LIB_TAG_DOIT) == 0)
+ id->lib->id.tag |= LIB_TAG_DOIT;
}
}
diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c
index abba61310a4..7821946eb6e 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -151,10 +151,10 @@ static void mesh_looptri_nearest_point(void *userdata, int index, const float co
}
}
/* copy of function above (warning, should de-duplicate with editmesh_bvh.c) */
-static void editmesh_faces_nearest_point(void *userdata, int index, const float co[3], BVHTreeNearest *nearest)
+static void editmesh_looptri_nearest_point(void *userdata, int index, const float co[3], BVHTreeNearest *nearest)
{
- const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata;
- BMEditMesh *em = data->em_evil;
+ const BVHTreeFromEditMesh *data = userdata;
+ BMEditMesh *em = data->em;
const BMLoop **ltri = (const BMLoop **)em->looptris[index];
const float *t0, *t1, *t2;
@@ -240,10 +240,10 @@ static void mesh_looptri_spherecast(void *userdata, int index, const BVHTreeRay
}
}
/* copy of function above (warning, should de-duplicate with editmesh_bvh.c) */
-static void editmesh_faces_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+static void editmesh_looptri_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
{
- const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata;
- BMEditMesh *em = data->em_evil;
+ const BVHTreeFromEditMesh *data = (BVHTreeFromEditMesh *)userdata;
+ BMEditMesh *em = data->em;
const BMLoop **ltri = (const BMLoop **)em->looptris[index];
const float *t0, *t1, *t2;
@@ -296,7 +296,7 @@ static void mesh_edges_nearest_point(void *userdata, int index, const float co[3
/* Helper, does all the point-spherecast work actually. */
static void mesh_verts_spherecast_do(
- const BVHTreeFromMesh *UNUSED(data), int index, const float v[3], const BVHTreeRay *ray, BVHTreeRayHit *hit)
+ int index, const float v[3], const BVHTreeRay *ray, BVHTreeRayHit *hit)
{
float dist;
const float *r1;
@@ -314,6 +314,14 @@ static void mesh_verts_spherecast_do(
}
}
+static void editmesh_verts_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+{
+ const BVHTreeFromEditMesh *data = userdata;
+ BMVert *eve = BM_vert_at_index(data->em->bm, index);
+
+ mesh_verts_spherecast_do(index, eve->co, ray, hit);
+}
+
/* Callback to bvh tree raycast. The tree must have been built using bvhtree_from_mesh_verts.
* userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */
static void mesh_verts_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
@@ -321,7 +329,7 @@ static void mesh_verts_spherecast(void *userdata, int index, const BVHTreeRay *r
const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
const float *v = data->vert[index].co;
- mesh_verts_spherecast_do(data, index, v, ray, hit);
+ mesh_verts_spherecast_do(index, v, ray, hit);
}
/* Callback to bvh tree raycast. The tree must have been built using bvhtree_from_mesh_edges.
@@ -341,7 +349,7 @@ static void mesh_edges_spherecast(void *userdata, int index, const BVHTreeRay *r
/* In case we get a zero-length edge, handle it as a point! */
if (equals_v3v3(v1, v2)) {
- mesh_verts_spherecast_do(data, index, v1, ray, hit);
+ mesh_verts_spherecast_do(index, v1, ray, hit);
return;
}
@@ -380,78 +388,64 @@ static void mesh_edges_spherecast(void *userdata, int index, const BVHTreeRay *r
/** \name Vertex Builder
* \{ */
-static BVHTree *bvhtree_from_mesh_verts_create_tree(
+static BVHTree *bvhtree_from_editmesh_verts_create_tree(
float epsilon, int tree_type, int axis,
- BMEditMesh *em, const int *index_array,
- MVert *vert, const int numVerts,
- BLI_bitmap *mask, int numVerts_active)
+ BMEditMesh *em, const int verts_num,
+ const BLI_bitmap *verts_mask, int verts_num_active)
{
BVHTree *tree = NULL;
- BMVert *eve = NULL;
int i;
- int index = 0;
- if (em != NULL) {
- BM_mesh_elem_table_ensure(em->bm, BM_VERT);
+ BM_mesh_elem_table_ensure(em->bm, BM_VERT);
+ if (verts_mask) {
+ BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
}
- if (vert) {
- if (mask && numVerts_active < 0) {
- numVerts_active = 0;
- for (i = 0; i < numVerts; i++) {
- if (BLI_BITMAP_TEST_BOOL(mask, i)) {
- if (em != NULL) {
- if (index_array) {
- index = index_array[i];
- if (index == ORIGINDEX_NONE) {
- continue;
- }
- }
- else {
- index = i;
- }
-
- eve = BM_vert_at_index(em->bm, index);
- if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN) ||
- BM_elem_flag_test(eve, BM_ELEM_SELECT))
- {
- continue;
- }
- }
- numVerts_active++;
- }
+ else {
+ verts_num_active = verts_num;
+ }
+
+ tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
+
+ if (tree) {
+ BMIter iter;
+ BMVert *eve;
+ BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+ if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
+ continue;
}
+ BLI_bvhtree_insert(tree, i, eve->co, 1);
}
- else if (!mask) {
- numVerts_active = numVerts;
+ BLI_assert(BLI_bvhtree_get_size(tree) == verts_num_active);
+ BLI_bvhtree_balance(tree);
+ }
+
+ return tree;
+}
+
+static BVHTree *bvhtree_from_mesh_verts_create_tree(
+ float epsilon, int tree_type, int axis,
+ MVert *vert, const int verts_num,
+ const BLI_bitmap *verts_mask, int verts_num_active)
+{
+ BVHTree *tree = NULL;
+ int i;
+ if (vert) {
+ if (verts_mask) {
+ BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
+ }
+ else {
+ verts_num_active = verts_num;
}
- tree = BLI_bvhtree_new(numVerts_active, epsilon, tree_type, axis);
+ tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
if (tree) {
- for (i = 0; i < numVerts; i++) {
- if (mask && !BLI_BITMAP_TEST_BOOL(mask, i)) {
+ for (i = 0; i < verts_num; i++) {
+ if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
continue;
}
- if (em != NULL) {
- if (index_array) {
- index = index_array[i];
- if (index == ORIGINDEX_NONE) {
- continue;
- }
- }
- else {
- index = i;
- }
-
- eve = BM_vert_at_index(em->bm, index);
- if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN) ||
- BM_elem_flag_test(eve, BM_ELEM_SELECT))
- {
- continue;
- }
- }
BLI_bvhtree_insert(tree, i, vert[i].co, 1);
}
-
+ BLI_assert(BLI_bvhtree_get_size(tree) == verts_num_active);
BLI_bvhtree_balance(tree);
}
}
@@ -488,17 +482,51 @@ static void bvhtree_from_mesh_verts_setup_data(
}
}
+/* Builds a bvh tree where nodes are the vertices of the given em */
+BVHTree *bvhtree_from_editmesh_verts_ex(
+ BVHTreeFromEditMesh *data, BMEditMesh *em,
+ const BLI_bitmap *verts_mask, int verts_num_active,
+ float epsilon, int tree_type, int axis)
+{
+ int vert_num = em->bm->totvert;
+
+ BVHTree *tree = bvhtree_from_editmesh_verts_create_tree(
+ epsilon, tree_type, axis,
+ em, vert_num, verts_mask, verts_num_active);
+
+ if (tree) {
+ memset(data, 0, sizeof(*data));
+ data->tree = tree;
+ data->em = em;
+ data->nearest_callback = NULL;
+ data->raycast_callback = editmesh_verts_spherecast;
+ data->nearest_to_ray_callback = NULL;
+ }
+
+ return tree;
+}
+BVHTree *bvhtree_from_editmesh_verts(
+ BVHTreeFromEditMesh *data, BMEditMesh *em,
+ float epsilon, int tree_type, int axis)
+{
+ return bvhtree_from_editmesh_verts_ex(
+ data, em,
+ NULL, -1,
+ epsilon, tree_type, axis);
+}
+
+
/* Builds a bvh tree where nodes are the vertices of the given dm */
-BVHTree *bvhtree_from_mesh_verts(BVHTreeFromMesh *data, DerivedMesh *dm, float epsilon, int tree_type, int axis)
+BVHTree *bvhtree_from_mesh_verts(
+ BVHTreeFromMesh *data, DerivedMesh *dm,
+ float epsilon, int tree_type, int axis)
{
- BMEditMesh *em = data->em_evil;
- const int bvhcache_type = em ? BVHTREE_FROM_VERTS_EDITMESH_SNAP : BVHTREE_FROM_VERTS;
BVHTree *tree;
MVert *vert;
bool vert_allocated;
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- tree = bvhcache_find(&dm->bvhCache, bvhcache_type);
+ tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_VERTS);
BLI_rw_mutex_unlock(&cache_rwlock);
vert = DM_get_vert_array(dm, &vert_allocated);
@@ -506,26 +534,20 @@ BVHTree *bvhtree_from_mesh_verts(BVHTreeFromMesh *data, DerivedMesh *dm, float e
/* Not in cache */
if (tree == NULL) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(&dm->bvhCache, bvhcache_type);
+ tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_VERTS);
if (tree == NULL) {
- int vert_num, *index_array = NULL;
- if (em != NULL) {
- vert_num = em->bm->totvert;
- index_array = dm->getVertDataArray(dm, CD_ORIGINDEX);
- }
- else {
- vert_num = dm->getNumVerts(dm);
- BLI_assert(vert_num != 0);
- }
+
+ int vert_num = dm->getNumVerts(dm);
+ BLI_assert(vert_num != 0);
+
tree = bvhtree_from_mesh_verts_create_tree(
epsilon, tree_type, axis,
- em, index_array,
vert, vert_num, NULL, -1);
if (tree) {
/* Save on cache for later use */
/* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(&dm->bvhCache, tree, bvhcache_type);
+ bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_VERTS);
}
}
BLI_rw_mutex_unlock(&cache_rwlock);
@@ -544,14 +566,15 @@ BVHTree *bvhtree_from_mesh_verts(BVHTreeFromMesh *data, DerivedMesh *dm, float e
* Builds a bvh tree where nodes are the given vertices (note: does not copy given mverts!).
* \param vert_allocated if true, vert freeing will be done when freeing data.
* \param mask if not null, true elements give which vert to add to BVH tree.
- * \param numVerts_active if >= 0, number of active verts to add to BVH tree (else will be computed from mask).
+ * \param verts_num_active if >= 0, number of active verts to add to BVH tree (else will be computed from mask).
*/
BVHTree *bvhtree_from_mesh_verts_ex(
- BVHTreeFromMesh *data, MVert *vert, const int numVerts, const bool vert_allocated,
- BLI_bitmap *mask, int numVerts_active,
+ BVHTreeFromMesh *data, MVert *vert, const int verts_num, const bool vert_allocated,
+ const BLI_bitmap *verts_mask, int verts_num_active,
float epsilon, int tree_type, int axis)
{
- BVHTree *tree = bvhtree_from_mesh_verts_create_tree(epsilon, tree_type, axis, NULL, NULL, vert, numVerts, mask, numVerts_active);
+ BVHTree *tree = bvhtree_from_mesh_verts_create_tree(
+ epsilon, tree_type, axis, vert, verts_num, verts_mask, verts_num_active);
/* Setup BVHTreeFromMesh */
bvhtree_from_mesh_verts_setup_data(data, tree, false, epsilon, vert, vert_allocated);
@@ -568,7 +591,9 @@ BVHTree *bvhtree_from_mesh_verts_ex(
* \{ */
/* Builds a bvh tree where nodes are the edges of the given dm */
-BVHTree *bvhtree_from_mesh_edges(BVHTreeFromMesh *data, DerivedMesh *dm, float epsilon, int tree_type, int axis)
+BVHTree *bvhtree_from_mesh_edges(
+ BVHTreeFromMesh *data, DerivedMesh *dm,
+ float epsilon, int tree_type, int axis)
{
BVHTree *tree;
MVert *vert;
@@ -576,7 +601,7 @@ BVHTree *bvhtree_from_mesh_edges(BVHTreeFromMesh *data, DerivedMesh *dm, float e
bool vert_allocated, edge_allocated;
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_EDGES);
+ tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_EDGES);
BLI_rw_mutex_unlock(&cache_rwlock);
vert = DM_get_vert_array(dm, &vert_allocated);
@@ -585,7 +610,7 @@ BVHTree *bvhtree_from_mesh_edges(BVHTreeFromMesh *data, DerivedMesh *dm, float e
/* Not in cache */
if (tree == NULL) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_EDGES);
+ tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_EDGES);
if (tree == NULL) {
int i;
int numEdges = dm->getNumEdges(dm);
@@ -655,109 +680,41 @@ BVHTree *bvhtree_from_mesh_edges(BVHTreeFromMesh *data, DerivedMesh *dm, float e
static BVHTree *bvhtree_from_mesh_faces_create_tree(
float epsilon, int tree_type, int axis,
- BMEditMesh *em, const bool em_all,
- MVert *vert, MFace *face, const int numFaces,
- BLI_bitmap *mask, int numFaces_active)
+ MVert *vert, MFace *face, const int faces_num,
+ const BLI_bitmap *faces_mask, int faces_num_active)
{
BVHTree *tree = NULL;
int i;
- if (numFaces) {
- if (mask && numFaces_active < 0) {
- numFaces_active = 0;
- for (i = 0; i < numFaces; i++) {
- if (BLI_BITMAP_TEST_BOOL(mask, i)) {
- numFaces_active++;
- }
- }
+ if (faces_num) {
+ if (faces_mask) {
+ BLI_assert(IN_RANGE_INCL(faces_num_active, 0, faces_num));
}
- else if (!mask) {
- numFaces_active = numFaces;
+ else {
+ faces_num_active = faces_num;
}
/* Create a bvh-tree of the given target */
/* printf("%s: building BVH, total=%d\n", __func__, numFaces); */
- tree = BLI_bvhtree_new(numFaces_active, epsilon, tree_type, axis);
+ tree = BLI_bvhtree_new(faces_num_active, epsilon, tree_type, axis);
if (tree) {
- if (em) {
- const struct BMLoop *(*looptris)[3] = (void *)em->looptris;
-
- /* avoid double-up on face searches for quads-ngons */
- bool insert_prev = false;
- BMFace *f_prev = NULL;
-
- /* data->em_evil is only set for snapping, and only for the mesh of the object
- * which is currently open in edit mode. When set, the bvhtree should not contain
- * faces that will interfere with snapping (e.g. faces that are hidden/selected
- * or faces that have selected verts). */
-
- /* Insert BMesh-tessellation triangles into the bvh tree, unless they are hidden
- * and/or selected. Even if the faces themselves are not selected for the snapped
- * transform, having a vertex selected means the face (and thus it's tessellated
- * triangles) will be moving and will not be a good snap targets. */
- for (i = 0; i < numFaces; i++) {
- const BMLoop **ltri = looptris[i];
- BMFace *f = ltri[0]->f;
- bool insert = mask ? BLI_BITMAP_TEST_BOOL(mask, i) : true;
-
- /* Start with the assumption the triangle should be included for snapping. */
- if (f == f_prev) {
- insert = insert_prev;
- }
- else if (insert) {
- if (em_all) {
- /* pass */
- }
- else if (BM_elem_flag_test(f, BM_ELEM_SELECT) || BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
- /* Don't insert triangles tessellated from faces that are hidden or selected */
- insert = false;
- }
- else {
- BMLoop *l_iter, *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- if (BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
- /* Don't insert triangles tessellated from faces that have any selected verts */
- insert = false;
- break;
- }
- } while ((l_iter = l_iter->next) != l_first);
- }
-
- /* skip if face doesn't change */
- f_prev = f;
- insert_prev = insert;
+ if (vert && face) {
+ for (i = 0; i < faces_num; i++) {
+ float co[4][3];
+ if (faces_mask && !BLI_BITMAP_TEST_BOOL(faces_mask, i)) {
+ continue;
}
- if (insert) {
- /* No reason found to block hit-testing the triangle for snap, so insert it now.*/
- float co[3][3];
- copy_v3_v3(co[0], ltri[0]->v->co);
- copy_v3_v3(co[1], ltri[1]->v->co);
- copy_v3_v3(co[2], ltri[2]->v->co);
+ copy_v3_v3(co[0], vert[face[i].v1].co);
+ copy_v3_v3(co[1], vert[face[i].v2].co);
+ copy_v3_v3(co[2], vert[face[i].v3].co);
+ if (face[i].v4)
+ copy_v3_v3(co[3], vert[face[i].v4].co);
- BLI_bvhtree_insert(tree, i, co[0], 3);
- }
- }
- }
- else {
- if (vert && face) {
- for (i = 0; i < numFaces; i++) {
- float co[4][3];
- if (mask && !BLI_BITMAP_TEST_BOOL(mask, i)) {
- continue;
- }
-
- copy_v3_v3(co[0], vert[face[i].v1].co);
- copy_v3_v3(co[1], vert[face[i].v2].co);
- copy_v3_v3(co[2], vert[face[i].v3].co);
- if (face[i].v4)
- copy_v3_v3(co[3], vert[face[i].v4].co);
-
- BLI_bvhtree_insert(tree, i, co[0], face[i].v4 ? 4 : 3);
- }
+ BLI_bvhtree_insert(tree, i, co[0], face[i].v4 ? 4 : 3);
}
}
+ BLI_assert(BLI_bvhtree_get_size(tree) == faces_num_active);
BLI_bvhtree_balance(tree);
}
}
@@ -766,33 +723,24 @@ static BVHTree *bvhtree_from_mesh_faces_create_tree(
}
static void bvhtree_from_mesh_faces_setup_data(
- BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached,
- float epsilon, BMEditMesh *em,
+ BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached, float epsilon,
MVert *vert, const bool vert_allocated,
MFace *face, const bool face_allocated)
{
memset(data, 0, sizeof(*data));
- data->em_evil = em;
if (tree) {
data->tree = tree;
data->cached = is_cached;
- if (em) {
- data->nearest_callback = editmesh_faces_nearest_point;
- data->raycast_callback = editmesh_faces_spherecast;
- data->nearest_to_ray_callback = NULL;
- }
- else {
- data->nearest_callback = mesh_faces_nearest_point;
- data->raycast_callback = mesh_faces_spherecast;
- data->nearest_to_ray_callback = NULL;
-
- data->vert = vert;
- data->vert_allocated = vert_allocated;
- data->face = face;
- data->face_allocated = face_allocated;
- }
+ data->nearest_callback = mesh_faces_nearest_point;
+ data->raycast_callback = mesh_faces_spherecast;
+ data->nearest_to_ray_callback = NULL;
+
+ data->vert = vert;
+ data->vert_allocated = vert_allocated;
+ data->face = face;
+ data->face_allocated = face_allocated;
data->sphere_radius = epsilon;
}
@@ -807,54 +755,37 @@ static void bvhtree_from_mesh_faces_setup_data(
}
/* Builds a bvh tree where nodes are the tesselated faces of the given dm */
-BVHTree *bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *dm, float epsilon, int tree_type, int axis)
+BVHTree *bvhtree_from_mesh_faces(
+ BVHTreeFromMesh *data, DerivedMesh *dm,
+ float epsilon, int tree_type, int axis)
{
- BMEditMesh *em = data->em_evil;
- const int bvhcache_type = em ?
- (data->em_evil_all ? BVHTREE_FROM_FACES_EDITMESH_ALL : BVHTREE_FROM_FACES_EDITMESH_SNAP) :
- BVHTREE_FROM_FACES;
BVHTree *tree;
MVert *vert = NULL;
MFace *face = NULL;
bool vert_allocated = false, face_allocated = false;
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- tree = bvhcache_find(&dm->bvhCache, bvhcache_type);
+ tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_FACES);
BLI_rw_mutex_unlock(&cache_rwlock);
- if (em == NULL) {
- vert = DM_get_vert_array(dm, &vert_allocated);
- face = DM_get_tessface_array(dm, &face_allocated);
- }
+ vert = DM_get_vert_array(dm, &vert_allocated);
+ face = DM_get_tessface_array(dm, &face_allocated);
/* Not in cache */
if (tree == NULL) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(&dm->bvhCache, bvhcache_type);
+ tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_FACES);
if (tree == NULL) {
- int numFaces;
-
- /* BMESH specific check that we have tessfaces,
- * we _could_ tessellate here but rather not - campbell
- *
- * this assert checks we have tessfaces,
- * if not caller should use DM_ensure_tessface() */
- if (em) {
- numFaces = em->tottri;
- }
- else {
- numFaces = dm->getNumTessFaces(dm);
- BLI_assert(!(numFaces == 0 && dm->getNumPolys(dm) != 0));
- }
+ int numFaces = dm->getNumTessFaces(dm);
+ BLI_assert(!(numFaces == 0 && dm->getNumPolys(dm) != 0));
tree = bvhtree_from_mesh_faces_create_tree(
epsilon, tree_type, axis,
- em, (bvhcache_type == BVHTREE_FROM_FACES_EDITMESH_ALL),
vert, face, numFaces, NULL, -1);
if (tree) {
/* Save on cache for later use */
/* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(&dm->bvhCache, tree, bvhcache_type);
+ bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_FACES);
}
}
BLI_rw_mutex_unlock(&cache_rwlock);
@@ -864,7 +795,7 @@ BVHTree *bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *dm, float e
}
/* Setup BVHTreeFromMesh */
- bvhtree_from_mesh_faces_setup_data(data, tree, true, epsilon, em, vert, vert_allocated, face, face_allocated);
+ bvhtree_from_mesh_faces_setup_data(data, tree, true, epsilon, vert, vert_allocated, face, face_allocated);
return data->tree;
}
@@ -879,16 +810,16 @@ BVHTree *bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *dm, float e
BVHTree *bvhtree_from_mesh_faces_ex(
BVHTreeFromMesh *data, MVert *vert, const bool vert_allocated,
MFace *face, const int numFaces, const bool face_allocated,
- BLI_bitmap *mask, int numFaces_active, float epsilon, int tree_type, int axis)
+ const BLI_bitmap *faces_mask, int faces_num_active,
+ float epsilon, int tree_type, int axis)
{
BVHTree *tree = bvhtree_from_mesh_faces_create_tree(
epsilon, tree_type, axis,
- NULL, false,
vert, face, numFaces,
- mask, numFaces_active);
+ faces_mask, faces_num_active);
/* Setup BVHTreeFromMesh */
- bvhtree_from_mesh_faces_setup_data(data, tree, false, epsilon, NULL, vert, vert_allocated, face, face_allocated);
+ bvhtree_from_mesh_faces_setup_data(data, tree, false, epsilon, vert, vert_allocated, face, face_allocated);
return data->tree;
}
@@ -901,25 +832,19 @@ BVHTree *bvhtree_from_mesh_faces_ex(
/** \name LoopTri Face Builder
* \{ */
-static BVHTree *bvhtree_from_mesh_looptri_create_tree(
+static BVHTree *bvhtree_from_editmesh_looptri_create_tree(
float epsilon, int tree_type, int axis,
- BMEditMesh *em, const bool em_all,
- const MVert *vert, const MLoop *mloop, const MLoopTri *looptri, const int looptri_num,
- BLI_bitmap *mask, int looptri_num_active)
+ BMEditMesh *em, const int looptri_num,
+ const BLI_bitmap *looptri_mask, int looptri_num_active)
{
BVHTree *tree = NULL;
int i;
if (looptri_num) {
- if (mask && looptri_num_active < 0) {
- looptri_num_active = 0;
- for (i = 0; i < looptri_num; i++) {
- if (BLI_BITMAP_TEST_BOOL(mask, i)) {
- looptri_num_active++;
- }
- }
+ if (looptri_mask) {
+ BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptri_num));
}
- else if (!mask) {
+ else {
looptri_num_active = looptri_num;
}
@@ -930,52 +855,13 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree(
if (em) {
const struct BMLoop *(*looptris)[3] = (void *)em->looptris;
- /* avoid double-up on face searches for quads-ngons */
- bool insert_prev = false;
- BMFace *f_prev = NULL;
-
- /* data->em_evil is only set for snapping, and only for the mesh of the object
- * which is currently open in edit mode. When set, the bvhtree should not contain
- * faces that will interfere with snapping (e.g. faces that are hidden/selected
- * or faces that have selected verts). */
-
/* Insert BMesh-tessellation triangles into the bvh tree, unless they are hidden
* and/or selected. Even if the faces themselves are not selected for the snapped
* transform, having a vertex selected means the face (and thus it's tessellated
* triangles) will be moving and will not be a good snap targets. */
for (i = 0; i < looptri_num; i++) {
const BMLoop **ltri = looptris[i];
- BMFace *f = ltri[0]->f;
- bool insert = mask ? BLI_BITMAP_TEST_BOOL(mask, i) : true;
-
- /* Start with the assumption the triangle should be included for snapping. */
- if (f == f_prev) {
- insert = insert_prev;
- }
- else if (insert) {
- if (em_all) {
- /* pass */
- }
- else if (BM_elem_flag_test(f, BM_ELEM_SELECT) || BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
- /* Don't insert triangles tessellated from faces that are hidden or selected */
- insert = false;
- }
- else {
- BMLoop *l_iter, *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- if (BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
- /* Don't insert triangles tessellated from faces that have any selected verts */
- insert = false;
- break;
- }
- } while ((l_iter = l_iter->next) != l_first);
- }
-
- /* skip if face doesn't change */
- f_prev = f;
- insert_prev = insert;
- }
+ bool insert = looptri_mask ? BLI_BITMAP_TEST_BOOL(looptri_mask, i) : true;
if (insert) {
/* No reason found to block hit-testing the triangle for snap, so insert it now.*/
@@ -988,22 +874,49 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree(
}
}
}
- else {
- if (vert && looptri) {
- for (i = 0; i < looptri_num; i++) {
- float co[3][3];
- if (mask && !BLI_BITMAP_TEST_BOOL(mask, i)) {
- continue;
- }
+ BLI_assert(BLI_bvhtree_get_size(tree) == looptri_num_active);
+ BLI_bvhtree_balance(tree);
+ }
+ }
- copy_v3_v3(co[0], vert[mloop[looptri[i].tri[0]].v].co);
- copy_v3_v3(co[1], vert[mloop[looptri[i].tri[1]].v].co);
- copy_v3_v3(co[2], vert[mloop[looptri[i].tri[2]].v].co);
+ return tree;
+}
- BLI_bvhtree_insert(tree, i, co[0], 3);
+static BVHTree *bvhtree_from_mesh_looptri_create_tree(
+ float epsilon, int tree_type, int axis,
+ const MVert *vert, const MLoop *mloop, const MLoopTri *looptri, const int looptri_num,
+ const BLI_bitmap *looptri_mask, int looptri_num_active)
+{
+ BVHTree *tree = NULL;
+ int i;
+
+ if (looptri_num) {
+ if (looptri_mask) {
+ BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptri_num));
+ }
+ else {
+ looptri_num_active = looptri_num;
+ }
+
+ /* Create a bvh-tree of the given target */
+ /* printf("%s: building BVH, total=%d\n", __func__, numFaces); */
+ tree = BLI_bvhtree_new(looptri_num_active, epsilon, tree_type, axis);
+ if (tree) {
+ if (vert && looptri) {
+ for (i = 0; i < looptri_num; i++) {
+ float co[3][3];
+ if (looptri_mask && !BLI_BITMAP_TEST_BOOL(looptri_mask, i)) {
+ continue;
}
+
+ copy_v3_v3(co[0], vert[mloop[looptri[i].tri[0]].v].co);
+ copy_v3_v3(co[1], vert[mloop[looptri[i].tri[1]].v].co);
+ copy_v3_v3(co[2], vert[mloop[looptri[i].tri[2]].v].co);
+
+ BLI_bvhtree_insert(tree, i, co[0], 3);
}
}
+ BLI_assert(BLI_bvhtree_get_size(tree) == looptri_num_active);
BLI_bvhtree_balance(tree);
}
}
@@ -1012,36 +925,27 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree(
}
static void bvhtree_from_mesh_looptri_setup_data(
- BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached,
- float epsilon, BMEditMesh *em,
+ BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached, float epsilon,
const MVert *vert, const bool vert_allocated,
const MLoop *mloop, const bool loop_allocated,
const MLoopTri *looptri, const bool looptri_allocated)
{
memset(data, 0, sizeof(*data));
- data->em_evil = em;
if (tree) {
data->tree = tree;
data->cached = is_cached;
- if (em) {
- data->nearest_callback = editmesh_faces_nearest_point;
- data->raycast_callback = editmesh_faces_spherecast;
- data->nearest_to_ray_callback = NULL;
- }
- else {
- data->nearest_callback = mesh_looptri_nearest_point;
- data->raycast_callback = mesh_looptri_spherecast;
- data->nearest_to_ray_callback = NULL;
-
- data->vert = vert;
- data->vert_allocated = vert_allocated;
- data->loop = mloop;
- data->loop_allocated = loop_allocated;
- data->looptri = looptri;
- data->looptri_allocated = looptri_allocated;
- }
+ data->nearest_callback = mesh_looptri_nearest_point;
+ data->raycast_callback = mesh_looptri_spherecast;
+ data->nearest_to_ray_callback = NULL;
+
+ data->vert = vert;
+ data->vert_allocated = vert_allocated;
+ data->loop = mloop;
+ data->loop_allocated = loop_allocated;
+ data->looptri = looptri;
+ data->looptri_allocated = looptri_allocated;
data->sphere_radius = epsilon;
}
@@ -1059,16 +963,52 @@ static void bvhtree_from_mesh_looptri_setup_data(
}
/**
+ * Builds a bvh tree where nodes are the looptri faces of the given bm
+ */
+BVHTree *bvhtree_from_editmesh_looptri_ex(
+ BVHTreeFromEditMesh *data, BMEditMesh *em,
+ const BLI_bitmap *looptri_mask, int looptri_num_active,
+ float epsilon, int tree_type, int axis)
+{
+ /* BMESH specific check that we have tessfaces,
+ * we _could_ tessellate here but rather not - campbell
+ *
+ * this assert checks we have tessfaces,
+ * if not caller should use DM_ensure_tessface() */
+
+ BVHTree *tree = bvhtree_from_editmesh_looptri_create_tree(
+ epsilon, tree_type, axis,
+ em, em->tottri, looptri_mask, looptri_num_active);
+
+ if (tree) {
+ data->tree = tree;
+ data->nearest_callback = editmesh_looptri_nearest_point;
+ data->raycast_callback = editmesh_looptri_spherecast;
+ data->nearest_to_ray_callback = NULL;
+ data->sphere_radius = 0.0f;
+ data->em = em;
+ }
+ return tree;
+}
+
+BVHTree *bvhtree_from_editmesh_looptri(
+ BVHTreeFromEditMesh *data, BMEditMesh *em,
+ float epsilon, int tree_type, int axis)
+{
+ return bvhtree_from_editmesh_looptri_ex(
+ data, em, NULL, -1,
+ epsilon, tree_type, axis);
+}
+
+/**
* Builds a bvh tree where nodes are the looptri faces of the given dm
*
* \note for editmesh this is currently a duplicate of bvhtree_from_mesh_faces
*/
-BVHTree *bvhtree_from_mesh_looptri(BVHTreeFromMesh *data, DerivedMesh *dm, float epsilon, int tree_type, int axis)
+BVHTree *bvhtree_from_mesh_looptri(
+ BVHTreeFromMesh *data, DerivedMesh *dm,
+ float epsilon, int tree_type, int axis)
{
- BMEditMesh *em = data->em_evil;
- const int bvhcache_type = em ?
- (data->em_evil_all ? BVHTREE_FROM_FACES_EDITMESH_ALL : BVHTREE_FROM_FACES_EDITMESH_SNAP) :
- BVHTREE_FROM_LOOPTRI;
BVHTree *tree;
MVert *mvert = NULL;
MLoop *mloop = NULL;
@@ -1078,58 +1018,42 @@ BVHTree *bvhtree_from_mesh_looptri(BVHTreeFromMesh *data, DerivedMesh *dm, float
bool looptri_allocated = false;
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- tree = bvhcache_find(&dm->bvhCache, bvhcache_type);
+ tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_LOOPTRI);
BLI_rw_mutex_unlock(&cache_rwlock);
- if (em == NULL) {
- MPoly *mpoly;
- bool poly_allocated = false;
-
- mvert = DM_get_vert_array(dm, &vert_allocated);
- mpoly = DM_get_poly_array(dm, &poly_allocated);
+ MPoly *mpoly;
+ bool poly_allocated = false;
- mloop = DM_get_loop_array(dm, &loop_allocated);
- looptri = DM_get_looptri_array(
- dm,
- mvert,
- mpoly, dm->getNumPolys(dm),
- mloop, dm->getNumLoops(dm),
- &looptri_allocated);
+ mvert = DM_get_vert_array(dm, &vert_allocated);
+ mpoly = DM_get_poly_array(dm, &poly_allocated);
- if (poly_allocated) {
- MEM_freeN(mpoly);
- }
+ mloop = DM_get_loop_array(dm, &loop_allocated);
+ looptri = DM_get_looptri_array(
+ dm,
+ mvert,
+ mpoly, dm->getNumPolys(dm),
+ mloop, dm->getNumLoops(dm),
+ &looptri_allocated);
+ if (poly_allocated) {
+ MEM_freeN(mpoly);
}
/* Not in cache */
if (tree == NULL) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(&dm->bvhCache, bvhcache_type);
+ tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_LOOPTRI);
if (tree == NULL) {
- int looptri_num;
-
- /* BMESH specific check that we have tessfaces,
- * we _could_ tessellate here but rather not - campbell
- *
- * this assert checks we have tessfaces,
- * if not caller should use DM_ensure_tessface() */
- if (em) {
- looptri_num = em->tottri;
- }
- else {
- looptri_num = dm->getNumLoopTri(dm);
- BLI_assert(!(looptri_num == 0 && dm->getNumPolys(dm) != 0));
- }
+ int looptri_num = dm->getNumLoopTri(dm);
+ BLI_assert(!(looptri_num == 0 && dm->getNumPolys(dm) != 0));
tree = bvhtree_from_mesh_looptri_create_tree(
epsilon, tree_type, axis,
- em, (bvhcache_type == BVHTREE_FROM_FACES_EDITMESH_ALL),
mvert, mloop, looptri, looptri_num, NULL, -1);
if (tree) {
/* Save on cache for later use */
/* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(&dm->bvhCache, tree, bvhcache_type);
+ bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_LOOPTRI);
}
}
BLI_rw_mutex_unlock(&cache_rwlock);
@@ -1140,7 +1064,7 @@ BVHTree *bvhtree_from_mesh_looptri(BVHTreeFromMesh *data, DerivedMesh *dm, float
/* Setup BVHTreeFromMesh */
bvhtree_from_mesh_looptri_setup_data(
- data, tree, true, epsilon, em,
+ data, tree, true, epsilon,
mvert, vert_allocated,
mloop, loop_allocated,
looptri, looptri_allocated);
@@ -1153,18 +1077,17 @@ BVHTree *bvhtree_from_mesh_looptri_ex(
const struct MVert *vert, const bool vert_allocated,
const struct MLoop *mloop, const bool loop_allocated,
const struct MLoopTri *looptri, const int looptri_num, const bool looptri_allocated,
- BLI_bitmap *mask, int looptri_num_active,
+ const BLI_bitmap *looptri_mask, int looptri_num_active,
float epsilon, int tree_type, int axis)
{
BVHTree *tree = bvhtree_from_mesh_looptri_create_tree(
epsilon, tree_type, axis,
- NULL, false,
vert, mloop, looptri, looptri_num,
- mask, looptri_num_active);
+ looptri_mask, looptri_num_active);
/* Setup BVHTreeFromMesh */
bvhtree_from_mesh_looptri_setup_data(
- data, tree, false, epsilon, NULL,
+ data, tree, false, epsilon,
vert, vert_allocated,
mloop, loop_allocated,
looptri, looptri_allocated);
@@ -1175,6 +1098,15 @@ BVHTree *bvhtree_from_mesh_looptri_ex(
/** \} */
+/* Frees data allocated by a call to bvhtree_from_editmesh_*. */
+void free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh *data)
+{
+ if (data->tree) {
+ BLI_bvhtree_free(data->tree);
+ memset(data, 0, sizeof(*data));
+ }
+}
+
/* Frees data allocated by a call to bvhtree_from_mesh_*. */
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
{
@@ -1215,32 +1147,46 @@ typedef struct BVHCacheItem {
} BVHCacheItem;
-static void bvhcacheitem_set_if_match(void *_cached, void *_search)
+/**
+ * Queries a bvhcache for the cache bvhtree of the request type
+ */
+BVHTree *bvhcache_find(BVHCache *cache, int type)
{
- BVHCacheItem *cached = (BVHCacheItem *)_cached;
- BVHCacheItem *search = (BVHCacheItem *)_search;
-
- if (search->type == cached->type) {
- search->tree = cached->tree;
+ while (cache) {
+ const BVHCacheItem *item = cache->link;
+ if (item->type == type) {
+ return item->tree;
+ }
+ cache = cache->next;
}
-}
+ return NULL;
+}
-BVHTree *bvhcache_find(BVHCache *cache, int type)
+bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree)
{
- BVHCacheItem item;
- item.type = type;
- item.tree = NULL;
-
- BLI_linklist_apply(*cache, bvhcacheitem_set_if_match, &item);
- return item.tree;
+ while (cache) {
+ const BVHCacheItem *item = cache->link;
+ if (item->tree == tree) {
+ return true;
+ }
+ cache = cache->next;
+ }
+ return false;
}
-void bvhcache_insert(BVHCache *cache, BVHTree *tree, int type)
+/**
+ * Inserts a BVHTree of the given type under the cache
+ * After that the caller no longer needs to worry when to free the BVHTree
+ * as that will be done when the cache is freed.
+ *
+ * A call to this assumes that there was no previous cached tree of the given type
+ */
+void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type)
{
BVHCacheItem *item = NULL;
assert(tree != NULL);
- assert(bvhcache_find(cache, type) == NULL);
+ assert(bvhcache_find(*cache_p, type) == NULL);
item = MEM_mallocN(sizeof(BVHCacheItem), "BVHCacheItem");
assert(item != NULL);
@@ -1248,13 +1194,15 @@ void bvhcache_insert(BVHCache *cache, BVHTree *tree, int type)
item->type = type;
item->tree = tree;
- BLI_linklist_prepend(cache, item);
+ BLI_linklist_prepend(cache_p, item);
}
-
-void bvhcache_init(BVHCache *cache)
+/**
+ * inits and frees a bvhcache
+ */
+void bvhcache_init(BVHCache **cache_p)
{
- *cache = NULL;
+ *cache_p = NULL;
}
static void bvhcacheitem_free(void *_item)
@@ -1266,10 +1214,10 @@ static void bvhcacheitem_free(void *_item)
}
-void bvhcache_free(BVHCache *cache)
+void bvhcache_free(BVHCache **cache_p)
{
- BLI_linklist_free(*cache, (LinkNodeFreeFP)bvhcacheitem_free);
- *cache = NULL;
+ BLI_linklist_free(*cache_p, (LinkNodeFreeFP)bvhcacheitem_free);
+ *cache_p = NULL;
}
/** \} */
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index 6fd756e2788..96bac2c2f41 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -76,6 +76,8 @@ void BKE_camera_init(Camera *cam)
/* stereoscopy 3d */
cam->stereo.interocular_distance = 0.065f;
cam->stereo.convergence_distance = 30.f * 0.065f;
+ cam->stereo.pole_merge_angle_from = DEG2RAD(60.0f);
+ cam->stereo.pole_merge_angle_to = DEG2RAD(75.0f);
}
void *BKE_camera_add(Main *bmain, const char *name)
@@ -904,7 +906,7 @@ static Object *camera_multiview_advanced(Scene *scene, Object *camera, const cha
/* returns the camera to be used for render */
Object *BKE_camera_multiview_render(Scene *scene, Object *camera, const char *viewname)
{
- const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
+ const bool is_multiview = (camera != NULL) && (scene->r.scemode & R_MULTIVIEW) != 0;
if (!is_multiview) {
return camera;
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index 87dc08e5124..9c163990dd2 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -491,11 +491,12 @@ static void cdDM_drawFacesTex_common(
CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
const MPoly *mpoly = cddm->mpoly;
MTexPoly *mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY);
- const MLoopCol *mloopcol;
+ const MLoopCol *mloopcol = NULL;
int i;
int colType, start_element, tot_drawn;
const bool use_hide = (flag & DM_DRAW_SKIP_HIDDEN) != 0;
const bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0;
+ const bool use_colors = (flag & DM_DRAW_USE_COLORS) != 0;
int totpoly;
int next_actualFace;
int mat_index;
@@ -525,15 +526,17 @@ static void cdDM_drawFacesTex_common(
}
}
- colType = CD_TEXTURE_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- if (!mloopcol) {
- colType = CD_PREVIEW_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- }
- if (!mloopcol) {
- colType = CD_MLOOPCOL;
+ if (use_colors) {
+ colType = CD_TEXTURE_MLOOPCOL;
mloopcol = dm->getLoopDataArray(dm, colType);
+ if (!mloopcol) {
+ colType = CD_PREVIEW_MLOOPCOL;
+ mloopcol = dm->getLoopDataArray(dm, colType);
+ }
+ if (!mloopcol) {
+ colType = CD_MLOOPCOL;
+ mloopcol = dm->getLoopDataArray(dm, colType);
+ }
}
GPU_vertex_setup(dm);
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 9454ad62ed3..fa0960515b4 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -57,6 +57,7 @@ static void cloth_to_object (Object *ob, ClothModifierData *clmd, float (*verte
static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm );
static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float framenr, int first);
static void cloth_update_springs( ClothModifierData *clmd );
+static void cloth_update_spring_lengths( ClothModifierData *clmd, DerivedMesh *dm );
static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm );
static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm );
@@ -346,6 +347,10 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
/* Support for dynamic vertex groups, changing from frame to frame */
cloth_apply_vgroup ( clmd, result );
+
+ if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW )
+ cloth_update_spring_lengths ( clmd, result );
+
cloth_update_springs( clmd );
// TIMEIT_START(cloth_step)
@@ -569,6 +574,7 @@ int cloth_uses_vgroup(ClothModifierData *clmd)
{
return (((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SCALING ) ||
(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) ||
+ (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW) ||
(clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF)) &&
((clmd->sim_parms->vgroup_mass>0) ||
(clmd->sim_parms->vgroup_struct>0)||
@@ -609,6 +615,9 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
else
verts->goal= 0.0f;
+ /* Compute base cloth shrink weight */
+ verts->shrink_factor = 0.0f;
+
/* Reset vertex flags */
verts->flags &= ~CLOTH_VERT_FLAG_PINNED;
verts->flags &= ~CLOTH_VERT_FLAG_NOSELFCOLL;
@@ -646,16 +655,14 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
verts->flags |= CLOTH_VERT_FLAG_NOSELFCOLL;
}
}
-
+ }
+ if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW ) {
if (clmd->sim_parms->vgroup_shrink > 0) {
if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_shrink - 1)) {
- /* linear interpolation between min and max shrink factor based on weight */
- verts->shrink_factor = clmd->sim_parms->shrink_min * (1.0f - dvert->dw[j].weight) + clmd->sim_parms->shrink_max * dvert->dw [j].weight;
+ /* used for linear interpolation between min and max shrink factor based on weight */
+ verts->shrink_factor = dvert->dw[j].weight;
}
}
- else {
- verts->shrink_factor = clmd->sim_parms->shrink_min;
- }
}
}
}
@@ -663,6 +670,23 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
}
}
+static float cloth_shrink_factor(ClothModifierData *clmd, ClothVertex *verts, int i1, int i2)
+{
+ if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW ) {
+ /* linear interpolation between min and max shrink factor based on weight */
+ float base = 1.0f - clmd->sim_parms->shrink_min;
+ float delta = clmd->sim_parms->shrink_min - clmd->sim_parms->shrink_max;
+
+ float k1 = base + delta * verts[i1].shrink_factor;
+ float k2 = base + delta * verts[i2].shrink_factor;
+
+ /* Use geometrical mean to average two factors since it behaves better
+ for diagonals when a rectangle transforms into a trapezoid. */
+ return sqrtf(k1 * k2);
+ }
+ else
+ return 1.0f;
+}
static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float UNUSED(framenr), int first)
{
@@ -720,11 +744,11 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
mul_m4_v3(ob->obmat, verts->x);
if ( shapekey_rest ) {
- verts->xrest= shapekey_rest[i];
+ copy_v3_v3(verts->xrest, shapekey_rest[i]);
mul_m4_v3(ob->obmat, verts->xrest);
}
else
- verts->xrest = verts->x;
+ copy_v3_v3(verts->xrest, verts->x);
}
/* no GUI interface yet */
@@ -736,6 +760,8 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
else
verts->goal= 0.0f;
+ verts->shrink_factor = 0.0f;
+
verts->flags = 0;
copy_v3_v3 ( verts->xold, verts->x );
copy_v3_v3 ( verts->xconst, verts->x );
@@ -1079,6 +1105,53 @@ static void cloth_update_springs( ClothModifierData *clmd )
cloth_hair_update_bending_targets(clmd);
}
+/* Update spring rest lenght, for dynamically deformable cloth */
+static void cloth_update_spring_lengths( ClothModifierData *clmd, DerivedMesh *dm )
+{
+ Cloth *cloth = clmd->clothObject;
+ LinkNode *search = cloth->springs;
+ unsigned int struct_springs = 0;
+ unsigned int i = 0;
+ unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm);
+ float shrink_factor;
+
+ clmd->sim_parms->avg_spring_len = 0.0f;
+
+ for (i = 0; i < mvert_num; i++) {
+ cloth->verts[i].avg_spring_len = 0.0f;
+ }
+
+ while (search) {
+ ClothSpring *spring = search->link;
+
+ if ( spring->type != CLOTH_SPRING_TYPE_SEWING ) {
+ if ( spring->type & (CLOTH_SPRING_TYPE_STRUCTURAL | CLOTH_SPRING_TYPE_SHEAR | CLOTH_SPRING_TYPE_BENDING) )
+ shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
+ else
+ shrink_factor = 1.0f;
+
+ spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
+ }
+
+ if ( spring->type == CLOTH_SPRING_TYPE_STRUCTURAL ) {
+ clmd->sim_parms->avg_spring_len += spring->restlen;
+ cloth->verts[spring->ij].avg_spring_len += spring->restlen;
+ cloth->verts[spring->kl].avg_spring_len += spring->restlen;
+ struct_springs++;
+ }
+
+ search = search->next;
+ }
+
+ if (struct_springs > 0)
+ clmd->sim_parms->avg_spring_len /= struct_springs;
+
+ for (i = 0; i < mvert_num; i++) {
+ if (cloth->verts[i].spring_count > 0)
+ cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49f / ((float)cloth->verts[i].spring_count);
+ }
+}
+
BLI_INLINE void cross_identity_v3(float r[3][3], const float v[3])
{
zero_m3(r);
@@ -1118,7 +1191,7 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
{
Cloth *cloth = clmd->clothObject;
ClothSpring *spring = NULL, *tspring = NULL, *tspring2 = NULL;
- unsigned int struct_springs = 0, shear_springs=0, bend_springs = 0;
+ unsigned int struct_springs = 0, shear_springs=0, bend_springs = 0, struct_springs_real = 0;
unsigned int i = 0;
unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm);
unsigned int numedges = (unsigned int)dm->getNumEdges (dm);
@@ -1162,19 +1235,19 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
spring->type = CLOTH_SPRING_TYPE_SEWING;
}
else {
- if (clmd->sim_parms->vgroup_shrink > 0)
- shrink_factor = 1.0f - ((cloth->verts[spring->ij].shrink_factor + cloth->verts[spring->kl].shrink_factor) / 2.0f);
- else
- shrink_factor = 1.0f - clmd->sim_parms->shrink_min;
+ shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
spring->stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0f;
spring->type = CLOTH_SPRING_TYPE_STRUCTURAL;
+
+ clmd->sim_parms->avg_spring_len += spring->restlen;
+ cloth->verts[spring->ij].avg_spring_len += spring->restlen;
+ cloth->verts[spring->kl].avg_spring_len += spring->restlen;
+ cloth->verts[spring->ij].spring_count++;
+ cloth->verts[spring->kl].spring_count++;
+ struct_springs_real++;
}
- clmd->sim_parms->avg_spring_len += spring->restlen;
- cloth->verts[spring->ij].avg_spring_len += spring->restlen;
- cloth->verts[spring->kl].avg_spring_len += spring->restlen;
- cloth->verts[spring->ij].spring_count++;
- cloth->verts[spring->kl].spring_count++;
+
spring->flags = 0;
struct_springs++;
@@ -1186,11 +1259,12 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
}
}
- if (struct_springs > 0)
- clmd->sim_parms->avg_spring_len /= struct_springs;
+ if (struct_springs_real > 0)
+ clmd->sim_parms->avg_spring_len /= struct_springs_real;
for (i = 0; i < mvert_num; i++) {
- cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49f / ((float)cloth->verts[i].spring_count);
+ if (cloth->verts[i].spring_count > 0)
+ cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49f / ((float)cloth->verts[i].spring_count);
}
// shear springs
@@ -1212,10 +1286,7 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
mloop[mpoly[i].loopstart + (j + 0)].v,
mloop[mpoly[i].loopstart + (j + 2)].v);
- if (clmd->sim_parms->vgroup_shrink > 0)
- shrink_factor = 1.0f - ((cloth->verts[spring->ij].shrink_factor + cloth->verts[spring->kl].shrink_factor) / 2.0f);
- else
- shrink_factor = 1.0f - clmd->sim_parms->shrink_min;
+ shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
spring->type = CLOTH_SPRING_TYPE_SHEAR;
spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f;
@@ -1259,7 +1330,8 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
}
spring_verts_ordered_set(spring, tspring2->ij, index2);
- spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest);
+ shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
+ spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
spring->type = CLOTH_SPRING_TYPE_BENDING;
spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
BLI_edgeset_insert(edgeset, spring->ij, spring->kl);
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index d35762a6f13..8cac856b560 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -224,7 +224,7 @@ static int cloth_collision_response_static ( ClothModifierData *clmd, CollisionM
float w1, w2, w3, u1, u2, u3;
float v1[3], v2[3], relativeVelocity[3];
float magrelVel;
- float epsilon2 = BLI_bvhtree_getepsilon ( collmd->bvhtree );
+ float epsilon2 = BLI_bvhtree_get_epsilon ( collmd->bvhtree );
cloth1 = clmd->clothObject;
@@ -396,7 +396,7 @@ static CollPair* cloth_collision(ModifierData *md1, ModifierData *md2,
#endif
double distance = 0;
float epsilon1 = clmd->coll_parms->epsilon;
- float epsilon2 = BLI_bvhtree_getepsilon ( collmd->bvhtree );
+ float epsilon2 = BLI_bvhtree_get_epsilon ( collmd->bvhtree );
tri_a = &clmd->clothObject->tri[overlap->indexA];
tri_b = &collmd->tri[overlap->indexB];
@@ -909,7 +909,7 @@ static bool cloth_points_collision_response_static(ClothModifierData *clmd, Coll
// float w1, w2;
float u1, u2, u3;
float v1[3], v2_old[3], v2_new[3], v_rel_old[3], v_rel_new[3];
- float epsilon2 = BLI_bvhtree_getepsilon ( collmd->bvhtree );
+ float epsilon2 = BLI_bvhtree_get_epsilon ( collmd->bvhtree );
for ( ; collpair != collision_end; collpair++ ) {
float margin_distance = (float)(collpair->distance - (double)epsilon2);
@@ -1249,7 +1249,7 @@ int cloth_points_objcollision(Object *ob, ClothModifierData *clmd, float step, f
/* search for overlapping collision pairs */
overlap = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &result, NULL, NULL);
- epsilon = BLI_bvhtree_getepsilon(collmd->bvhtree);
+ epsilon = BLI_bvhtree_get_epsilon(collmd->bvhtree);
// go to next object if no overlap is there
if (result && overlap) {
@@ -1375,7 +1375,7 @@ void cloth_find_point_contacts(Object *ob, ClothModifierData *clmd, float step,
/* search for overlapping collision pairs */
overlap = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &result, NULL, NULL);
- epsilon = BLI_bvhtree_getepsilon(collmd->bvhtree);
+ epsilon = BLI_bvhtree_get_epsilon(collmd->bvhtree);
// go to next object if no overlap is there
if (result && overlap) {
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 1b9ac499e1f..a591d536b43 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -535,10 +535,10 @@ static void contarget_get_lattice_mat(Object *ob, const char *substring, float m
/* generic function to get the appropriate matrix for most target cases */
/* The cases where the target can be object data have not been implemented */
-static void constraint_target_to_mat4(Object *ob, const char *substring, float mat[4][4], short from, short to, float headtail)
+static void constraint_target_to_mat4(Object *ob, const char *substring, float mat[4][4], short from, short to, short flag, float headtail)
{
/* Case OBJECT */
- if (!strlen(substring)) {
+ if (substring[0] == '\0') {
copy_m4_m4(mat, ob->obmat);
BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false);
}
@@ -573,6 +573,58 @@ static void constraint_target_to_mat4(Object *ob, const char *substring, float m
/* skip length interpolation if set to head */
mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat);
}
+ else if ((pchan->bone) && (pchan->bone->segments > 1) && (flag & CONSTRAINT_BBONE_SHAPE)) {
+ /* use point along bbone */
+ Mat4 bbone[MAX_BBONE_SUBDIV];
+ float tempmat[4][4];
+ float loc[3], fac;
+
+ /* get bbone segments */
+ b_bone_spline_setup(pchan, 0, bbone);
+
+ /* figure out which segment(s) the headtail value falls in */
+ fac = (float)pchan->bone->segments * headtail;
+
+ if (fac >= pchan->bone->segments - 1) {
+ /* special case: end segment doesn't get created properly... */
+ float pt[3], sfac;
+ int index;
+
+ /* bbone points are in bonespace, so need to move to posespace first */
+ index = pchan->bone->segments - 1;
+ mul_v3_m4v3(pt, pchan->pose_mat, bbone[index].mat[3]);
+
+ /* interpolate between last segment point and the endpoint */
+ sfac = fac - (float)(pchan->bone->segments - 1); /* fac is just the "leftover" between penultimate and last points */
+ interp_v3_v3v3(loc, pt, pchan->pose_tail, sfac);
+ }
+ else {
+ /* get indices for finding interpolating between points along the bbone */
+ float pt_a[3], pt_b[3], pt[3];
+ int index_a, index_b;
+
+ index_a = floorf(fac);
+ CLAMP(index_a, 0, MAX_BBONE_SUBDIV - 1);
+
+ index_b = ceilf(fac);
+ CLAMP(index_b, 0, MAX_BBONE_SUBDIV - 1);
+
+ /* interpolate between these points */
+ copy_v3_v3(pt_a, bbone[index_a].mat[3]);
+ copy_v3_v3(pt_b, bbone[index_b].mat[3]);
+
+ interp_v3_v3v3(pt, pt_a, pt_b, fac - floorf(fac));
+
+ /* move the point from bone local space to pose space... */
+ mul_v3_m4v3(loc, pchan->pose_mat, pt);
+ }
+
+ /* use interpolated distance for subtarget */
+ copy_m4_m4(tempmat, pchan->pose_mat);
+ copy_v3_v3(tempmat[3], loc);
+
+ mul_m4_m4m4(mat, ob->obmat, tempmat);
+ }
else {
float tempmat[4][4], loc[3];
@@ -634,7 +686,7 @@ static bConstraintTypeInfo CTI_CONSTRNAME = {
static void default_get_tarmat(bConstraint *con, bConstraintOb *UNUSED(cob), bConstraintTarget *ct, float UNUSED(ctime))
{
if (VALID_CONS_TARGET(ct))
- constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
+ constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
else if (ct)
unit_m4(ct->matrix);
}
@@ -1102,7 +1154,7 @@ static void kinematic_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstrai
bKinematicConstraint *data = con->data;
if (VALID_CONS_TARGET(ct))
- constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
+ constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
else if (ct) {
if (data->flag & CONSTRAINT_IK_AUTO) {
Object *ob = cob->ob;
@@ -1985,7 +2037,7 @@ static void pycon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTa
/* firstly calculate the matrix the normal way, then let the py-function override
* this matrix if it needs to do so
*/
- constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
+ constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
/* only execute target calculation if allowed */
#ifdef WITH_PYTHON
@@ -2097,7 +2149,7 @@ static void actcon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintT
unit_m4(ct->matrix);
/* get the transform matrix of the target */
- constraint_target_to_mat4(ct->tar, ct->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
+ constraint_target_to_mat4(ct->tar, ct->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
/* determine where in transform range target is */
/* data->type is mapped as follows for backwards compatibility:
@@ -2143,29 +2195,26 @@ static void actcon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintT
}
else if (cob->type == CONSTRAINT_OBTYPE_BONE) {
Object workob;
- bPose *pose;
+ bPose pose = {0};
bPoseChannel *pchan, *tchan;
-
- /* make a temporary pose and evaluate using that */
- pose = MEM_callocN(sizeof(bPose), "pose");
-
+
/* make a copy of the bone of interest in the temp pose before evaluating action, so that it can get set
* - we need to manually copy over a few settings, including rotation order, otherwise this fails
*/
pchan = cob->pchan;
- tchan = BKE_pose_channel_verify(pose, pchan->name);
+ tchan = BKE_pose_channel_verify(&pose, pchan->name);
tchan->rotmode = pchan->rotmode;
/* evaluate action using workob (it will only set the PoseChannel in question) */
- what_does_obaction(cob->ob, &workob, pose, data->act, pchan->name, t);
+ what_does_obaction(cob->ob, &workob, &pose, data->act, pchan->name, t);
/* convert animation to matrices for use here */
BKE_pchan_calc_mat(tchan);
copy_m4_m4(ct->matrix, tchan->chan_mat);
/* Clean up */
- BKE_pose_free(pose);
+ BKE_pose_free_data(&pose);
}
else {
/* behavior undefined... */
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 4c099987404..8afb451f768 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -1402,14 +1402,14 @@ void BKE_nurb_makeCurve(Nurb *nu, float *coord_array, float *tilt_array, float *
}
}
- coord_fp = (float *)(((char *)coord_fp) + stride);
+ coord_fp = POINTER_OFFSET(coord_fp, stride);
if (tilt_fp)
- tilt_fp = (float *)(((char *)tilt_fp) + stride);
+ tilt_fp = POINTER_OFFSET(tilt_fp, stride);
if (radius_fp)
- radius_fp = (float *)(((char *)radius_fp) + stride);
+ radius_fp = POINTER_OFFSET(radius_fp, stride);
if (weight_fp)
- weight_fp = (float *)(((char *)weight_fp) + stride);
+ weight_fp = POINTER_OFFSET(weight_fp, stride);
u += ustep;
}
@@ -1440,7 +1440,7 @@ void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float
for (a = 0; a <= it; a++) {
*p = q0;
- p = (float *)(((char *)p) + stride);
+ p = POINTER_OFFSET(p, stride);
q0 += q1;
q1 += q2;
q2 += q3;
@@ -1465,7 +1465,7 @@ void BKE_curve_forward_diff_tangent_bezier(float q0, float q1, float q2, float q
for (a = 0; a <= it; a++) {
*p = q0;
- p = (float *)(((char *)p) + stride);
+ p = POINTER_OFFSET(p, stride);
q0 += q1;
q1 += q2;
}
@@ -1490,7 +1490,7 @@ static void forward_diff_bezier_cotangent(const float p0[3], const float p1[3],
( 6.0f * t) * p3[i];
}
normalize_v3(p);
- p = (float *)(((char *)p) + stride);
+ p = POINTER_OFFSET(p, stride);
}
}
@@ -2102,7 +2102,7 @@ static void alfa_bezpart(BezTriple *prevbezt, BezTriple *bezt, Nurb *nu, float *
*tilt_array = t[0] * pprev->alfa + t[1] * prevbezt->alfa + t[2] * bezt->alfa + t[3] * next->alfa;
}
- tilt_array = (float *)(((char *)tilt_array) + stride);
+ tilt_array = POINTER_OFFSET(tilt_array, stride);
}
if (radius_array) {
@@ -2123,7 +2123,7 @@ static void alfa_bezpart(BezTriple *prevbezt, BezTriple *bezt, Nurb *nu, float *
t[2] * bezt->radius + t[3] * next->radius;
}
- radius_array = (float *)(((char *)radius_array) + stride);
+ radius_array = POINTER_OFFSET(radius_array, stride);
}
if (weight_array) {
@@ -2131,7 +2131,7 @@ static void alfa_bezpart(BezTriple *prevbezt, BezTriple *bezt, Nurb *nu, float *
*weight_array = prevbezt->weight +
(bezt->weight - prevbezt->weight) * (3.0f * fac * fac - 2.0f * fac * fac * fac);
- weight_array = (float *)(((char *)weight_array) + stride);
+ weight_array = POINTER_OFFSET(weight_array, stride);
}
}
}
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index b0d0dc08126..de79a30bd60 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -1530,13 +1530,11 @@ void CustomData_realloc(CustomData *data, int totelem)
for (i = 0; i < data->totlayer; ++i) {
CustomDataLayer *layer = &data->layers[i];
const LayerTypeInfo *typeInfo;
- int size;
if (layer->flag & CD_FLAG_NOFREE) {
continue;
}
typeInfo = layerType_getInfo(layer->type);
- size = totelem * typeInfo->size;
- layer->data = MEM_reallocN(layer->data, size);
+ layer->data = MEM_reallocN(layer->data, (size_t)totelem * typeInfo->size);
}
}
@@ -1844,7 +1842,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, int typ
int totelem, const char *name)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- const int size = totelem * typeInfo->size;
+ const size_t size = (size_t)totelem * typeInfo->size;
int flag = 0, index = data->totlayer;
void *newlayerdata = NULL;
@@ -2064,7 +2062,7 @@ static void *customData_duplicate_referenced_layer_index(CustomData *data, const
const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
if (typeInfo->copy) {
- void *dst_data = MEM_mallocN(totelem * typeInfo->size, "CD duplicate ref layer");
+ void *dst_data = MEM_mallocN((size_t)totelem * typeInfo->size, "CD duplicate ref layer");
typeInfo->copy(layer->data, dst_data, totelem);
layer->data = dst_data;
}
@@ -2172,7 +2170,7 @@ void CustomData_copy_elements(int type, void *src_data_ofs, void *dst_data_ofs,
if (typeInfo->copy)
typeInfo->copy(src_data_ofs, dst_data_ofs, count);
else
- memcpy(dst_data_ofs, src_data_ofs, count * typeInfo->size);
+ memcpy(dst_data_ofs, src_data_ofs, (size_t)count * typeInfo->size);
}
static void CustomData_copy_data_layer(
@@ -2181,16 +2179,14 @@ static void CustomData_copy_data_layer(
int src_index, int dst_index, int count)
{
const LayerTypeInfo *typeInfo;
- int src_offset;
- int dst_offset;
const void *src_data = source->layers[src_i].data;
void *dst_data = dest->layers[dst_i].data;
typeInfo = layerType_getInfo(source->layers[src_i].type);
- src_offset = src_index * typeInfo->size;
- dst_offset = dst_index * typeInfo->size;
+ const size_t src_offset = (size_t)src_index * typeInfo->size;
+ const size_t dst_offset = (size_t)dst_index * typeInfo->size;
if (!count || !src_data || !dst_data) {
if (count && !(src_data == NULL && dst_data == NULL)) {
@@ -2201,14 +2197,16 @@ static void CustomData_copy_data_layer(
return;
}
- if (typeInfo->copy)
+ if (typeInfo->copy) {
typeInfo->copy(POINTER_OFFSET(src_data, src_offset),
POINTER_OFFSET(dst_data, dst_offset),
count);
- else
+ }
+ else {
memcpy(POINTER_OFFSET(dst_data, dst_offset),
POINTER_OFFSET(src_data, src_offset),
- count * typeInfo->size);
+ (size_t)count * typeInfo->size);
+ }
}
void CustomData_copy_data_named(const CustomData *source, CustomData *dest,
@@ -2270,7 +2268,7 @@ void CustomData_free_elem(CustomData *data, int index, int count)
typeInfo = layerType_getInfo(data->layers[i].type);
if (typeInfo->free) {
- int offset = index * typeInfo->size;
+ size_t offset = (size_t)index * typeInfo->size;
typeInfo->free(POINTER_OFFSET(data->layers[i].data, offset), count, typeInfo->size);
}
@@ -2281,7 +2279,7 @@ void CustomData_free_elem(CustomData *data, int index, int count)
#define SOURCE_BUF_SIZE 100
void CustomData_interp(const CustomData *source, CustomData *dest,
- int *src_indices, float *weights, float *sub_weights,
+ const int *src_indices, const float *weights, const float *sub_weights,
int count, int dest_index)
{
int src_i, dest_i;
@@ -2316,11 +2314,11 @@ void CustomData_interp(const CustomData *source, CustomData *dest,
void *src_data = source->layers[src_i].data;
for (j = 0; j < count; ++j) {
- sources[j] = POINTER_OFFSET(src_data, src_indices[j] * typeInfo->size);
+ sources[j] = POINTER_OFFSET(src_data, (size_t)src_indices[j] * typeInfo->size);
}
typeInfo->interp(sources, weights, sub_weights, count,
- POINTER_OFFSET(dest->layers[dest_i].data, dest_index * typeInfo->size));
+ POINTER_OFFSET(dest->layers[dest_i].data, (size_t)dest_index * typeInfo->size));
/* if there are multiple source & dest layers of the same type,
* we don't want to copy all source layers to the same dest, so
@@ -2349,7 +2347,7 @@ void CustomData_swap_corners(struct CustomData *data, int index, const int *corn
typeInfo = layerType_getInfo(data->layers[i].type);
if (typeInfo->swap) {
- const int offset = index * typeInfo->size;
+ const size_t offset = (size_t)index * typeInfo->size;
typeInfo->swap(POINTER_OFFSET(data->layers[i].data, offset), corner_indices);
}
@@ -2387,7 +2385,6 @@ void CustomData_swap(struct CustomData *data, const int index_a, const int index
void *CustomData_get(const CustomData *data, int index, int type)
{
- int offset;
int layer_index;
BLI_assert(index >= 0);
@@ -2397,7 +2394,7 @@ void *CustomData_get(const CustomData *data, int index, int type)
if (layer_index == -1) return NULL;
/* get the offset of the desired element */
- offset = layerType_getInfo(type)->size * index;
+ const size_t offset = (size_t)index * layerType_getInfo(type)->size;
return POINTER_OFFSET(data->layers[layer_index].data, offset);
}
@@ -2405,7 +2402,6 @@ void *CustomData_get(const CustomData *data, int index, int type)
void *CustomData_get_n(const CustomData *data, int type, int index, int n)
{
int layer_index;
- int offset;
BLI_assert(index >= 0 && n >= 0);
@@ -2413,7 +2409,7 @@ void *CustomData_get_n(const CustomData *data, int type, int index, int n)
layer_index = data->typemap[type];
if (layer_index == -1) return NULL;
- offset = layerType_getInfo(type)->size * index;
+ const size_t offset = (size_t)index * layerType_getInfo(type)->size;
return POINTER_OFFSET(data->layers[layer_index + n].data, offset);
}
@@ -2838,7 +2834,7 @@ void CustomData_bmesh_free_block_data(CustomData *data, void *block)
typeInfo = layerType_getInfo(data->layers[i].type);
if (typeInfo->free) {
- int offset = data->layers[i].offset;
+ const size_t offset = data->layers[i].offset;
typeInfo->free(POINTER_OFFSET(block, offset), 1, typeInfo->size);
}
}
@@ -3218,7 +3214,7 @@ void CustomData_to_bmesh_block(const CustomData *source, CustomData *dest,
int src_index, void **dest_block, bool use_default_init)
{
const LayerTypeInfo *typeInfo;
- int dest_i, src_i, src_offset;
+ int dest_i, src_i;
if (*dest_block == NULL)
CustomData_bmesh_alloc_block(dest, dest_block);
@@ -3247,7 +3243,7 @@ void CustomData_to_bmesh_block(const CustomData *source, CustomData *dest,
void *dest_data = POINTER_OFFSET(*dest_block, offset);
typeInfo = layerType_getInfo(dest->layers[dest_i].type);
- src_offset = src_index * typeInfo->size;
+ const size_t src_offset = (size_t)src_index * typeInfo->size;
if (typeInfo->copy)
typeInfo->copy(POINTER_OFFSET(src_data, src_offset), dest_data, 1);
@@ -3294,7 +3290,7 @@ void CustomData_from_bmesh_block(const CustomData *source, CustomData *dest,
const LayerTypeInfo *typeInfo = layerType_getInfo(dest->layers[dest_i].type);
int offset = source->layers[src_i].offset;
const void *src_data = POINTER_OFFSET(src_block, offset);
- void *dst_data = POINTER_OFFSET(dest->layers[dest_i].data, dst_index * typeInfo->size);
+ void *dst_data = POINTER_OFFSET(dest->layers[dest_i].data, (size_t)dst_index * typeInfo->size);
if (typeInfo->copy)
typeInfo->copy(src_data, dst_data, 1);
@@ -3311,12 +3307,12 @@ void CustomData_from_bmesh_block(const CustomData *source, CustomData *dest,
}
-void CustomData_file_write_info(int type, const char **structname, int *structnum)
+void CustomData_file_write_info(int type, const char **r_struct_name, int *r_struct_num)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- *structname = typeInfo->structname;
- *structnum = typeInfo->structnum;
+ *r_struct_name = typeInfo->structname;
+ *r_struct_num = typeInfo->structnum;
}
/**
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 73d64c23840..7842d561557 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -32,6 +32,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_kdtree.h"
+#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
@@ -65,6 +66,7 @@
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BKE_mesh_mapping.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_scene.h"
@@ -78,13 +80,11 @@
#include "RE_render_ext.h"
#include "RE_shader_ext.h"
-#ifdef _OPENMP
-# include <omp.h>
-#endif
+#include "atomic_ops.h"
/* could enable at some point but for now there are far too many conversions */
#ifdef __GNUC__
-# pragma GCC diagnostic ignored "-Wdouble-promotion"
+//# pragma GCC diagnostic ignored "-Wdouble-promotion"
#endif
/* precalculated gaussian factors for 5x super sampling */
@@ -122,7 +122,7 @@ static int neighY[8] = {0, 1, 1, 1, 0, -1, -1, -1};
/* dissolve inline function */
-BLI_INLINE void value_dissolve(float *r_value, const float time, const float scale, const int is_log)
+BLI_INLINE void value_dissolve(float *r_value, const float time, const float scale, const bool is_log)
{
*r_value = (is_log) ?
(*r_value) * (powf(MIN_WETNESS, 1.0f / (1.2f * time / scale))) :
@@ -137,19 +137,20 @@ typedef struct Bounds2D {
} Bounds2D;
typedef struct Bounds3D {
- int valid;
float min[3], max[3];
+ bool valid;
} Bounds3D;
typedef struct VolumeGrid {
int dim[3];
- Bounds3D grid_bounds; /* whole grid bounds */
+ Bounds3D grid_bounds; /* whole grid bounds */
+
+ Bounds3D *bounds; /* (x*y*z) precalculated grid cell bounds */
+ 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, access: (s_pos + s_num) */
- Bounds3D *bounds; /* (x*y*z) precalculated grid cell bounds */
- 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,
- * access: (s_pos+s_num) */
+ int *temp_t_index;
} VolumeGrid;
typedef struct Vec3f {
@@ -164,21 +165,21 @@ typedef struct BakeAdjPoint {
/* Surface data used while processing a frame */
typedef struct PaintBakeNormal {
float invNorm[3]; /* current pixel world-space inverted normal */
- float normal_scale; /* normal directional scale for displace mapping */
+ float normal_scale; /* normal directional scale for displace mapping */
} PaintBakeNormal;
/* Temp surface data used to process a frame */
typedef struct PaintBakeData {
/* point space data */
PaintBakeNormal *bNormal;
- int *s_pos; /* index to start reading point sample realCoord */
- int *s_num; /* num of realCoord samples */
- Vec3f *realCoord; /* current pixel center world-space coordinates for each sample
- * ordered as (s_pos+s_num)*/
+ int *s_pos; /* index to start reading point sample realCoord */
+ int *s_num; /* num of realCoord samples */
+ Vec3f *realCoord; /* current pixel center world-space coordinates for each sample ordered as (s_pos + s_num) */
Bounds3D mesh_bounds;
+ float dim[3];
/* adjacency info */
- BakeAdjPoint *bNeighs; /* current global neighbor distances and directions, if required */
+ BakeAdjPoint *bNeighs; /* current global neighbor distances and directions, if required */
double average_dist;
/* space partitioning */
VolumeGrid *grid; /* space partitioning grid to optimize brush checks */
@@ -187,11 +188,10 @@ typedef struct PaintBakeData {
Vec3f *velocity; /* speed vector in global space movement per frame, if required */
Vec3f *prev_velocity;
float *brush_velocity; /* special temp data for post-p velocity based brushes like smudge
- * 3 float dir vec + 1 float str */
+ * 3 float dir vec + 1 float str */
MVert *prev_verts; /* copy of previous frame vertices. used to observe surface movement */
float prev_obmat[4][4]; /* previous frame object matrix */
int clear; /* flag to check if surface was cleared/reset -> have to redo velocity etc. */
-
} PaintBakeData;
/* UV Image sequence format point */
@@ -200,8 +200,7 @@ typedef struct PaintUVPoint {
unsigned int tri_index, pixel_index; /* tri index on domain derived mesh */
unsigned int v1, v2, v3; /* vertex indexes */
- unsigned int neighbour_pixel; /* If this pixel isn't uv mapped to any face,
- * but it's neighboring pixel is */
+ unsigned int neighbour_pixel; /* If this pixel isn't uv mapped to any face, but it's neighboring pixel is */
} PaintUVPoint;
typedef struct ImgSeqFormatData {
@@ -213,8 +212,7 @@ typedef struct ImgSeqFormatData {
#define ADJ_ON_MESH_EDGE (1 << 0)
typedef struct PaintAdjData {
- int *n_target; /* array of neighboring point indexes,
- * for single sample use (n_index + neigh_num) */
+ 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 */
int *n_num; /* num of neighs for each point */
int *flags; /* vertex adjacency flags */
@@ -238,11 +236,10 @@ static int dynamicPaint_surfaceNumOfPoints(DynamicPaintSurface *surface)
return 0; /* not supported atm */
}
else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- if (!surface->canvas->dm) return 0; /* invalid derived mesh */
- return surface->canvas->dm->getNumVerts(surface->canvas->dm);
+ return (surface->canvas->dm) ? surface->canvas->dm->getNumVerts(surface->canvas->dm) : 0;
}
- else
- return 0;
+
+ return 0;
}
/* checks whether surface's format/type has realtime preview */
@@ -252,32 +249,16 @@ bool dynamicPaint_surfaceHasColorPreview(DynamicPaintSurface *surface)
return false;
}
else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
- surface->type == MOD_DPAINT_SURFACE_T_WAVE)
- {
- return false;
- }
- else {
- return true;
- }
- }
- else {
- return true;
+ return !ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE);
}
+
+ return true;
}
/* get currently active surface (in user interface) */
DynamicPaintSurface *get_activeSurface(DynamicPaintCanvasSettings *canvas)
{
- DynamicPaintSurface *surface = canvas->surfaces.first;
- int i;
-
- for (i = 0; surface; surface = surface->next) {
- if (i == canvas->active_sur)
- return surface;
- i++;
- }
- return NULL;
+ return BLI_findlink(&canvas->surfaces, canvas->active_sur);
}
/* set preview to first previewable surface */
@@ -291,8 +272,9 @@ void dynamicPaint_resetPreview(DynamicPaintCanvasSettings *canvas)
surface->flags |= MOD_DPAINT_PREVIEW;
done = true;
}
- else
+ else {
surface->flags &= ~MOD_DPAINT_PREVIEW;
+ }
}
}
@@ -324,8 +306,9 @@ bool dynamicPaint_outputLayerExists(struct DynamicPaintSurface *surface, Object
Mesh *me = ob->data;
return (CustomData_get_named_layer_index(&me->ldata, CD_MLOOPCOL, name) != -1);
}
- else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT)
- return (defgroup_name_index(ob, surface->output_name) != -1);
+ else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
+ return (defgroup_name_index(ob, name) != -1);
+ }
}
return false;
@@ -333,15 +316,16 @@ bool dynamicPaint_outputLayerExists(struct DynamicPaintSurface *surface, Object
static bool surface_duplicateOutputExists(void *arg, const char *name)
{
- DynamicPaintSurface *t_surface = (DynamicPaintSurface *)arg;
+ DynamicPaintSurface *t_surface = arg;
DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
for (; surface; surface = surface->next) {
- if (surface != t_surface && surface->type == t_surface->type &&
- surface->format == t_surface->format)
- {
- 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;
+ if (surface != t_surface && surface->type == t_surface->type && surface->format == t_surface->format) {
+ if ((surface->output_name[0] != '\0' && !BLI_path_cmp(name, surface->output_name)) ||
+ (surface->output_name2[0] != '\0' && !BLI_path_cmp(name, surface->output_name2)))
+ {
+ return true;
+ }
}
}
return false;
@@ -351,20 +335,25 @@ static void surface_setUniqueOutputName(DynamicPaintSurface *surface, char *base
{
char name[64];
BLI_strncpy(name, basename, sizeof(name)); /* in case basename is surface->name use a copy */
- 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));
+ if (output == 0) {
+ BLI_uniquename_cb(surface_duplicateOutputExists, surface, name, '.',
+ surface->output_name, sizeof(surface->output_name));
+ }
+ else if (output == 1) {
+ BLI_uniquename_cb(surface_duplicateOutputExists, surface, name, '.',
+ surface->output_name2, sizeof(surface->output_name2));
+ }
}
static bool surface_duplicateNameExists(void *arg, const char *name)
{
- DynamicPaintSurface *t_surface = (DynamicPaintSurface *)arg;
+ DynamicPaintSurface *t_surface = arg;
DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
for (; surface; surface = surface->next) {
- if (surface != t_surface && STREQ(name, surface->name)) return true;
+ if (surface != t_surface && STREQ(name, surface->name))
+ return true;
}
return false;
}
@@ -419,9 +408,7 @@ void dynamicPaintSurface_updateType(struct DynamicPaintSurface *surface)
static int surface_totalSamples(DynamicPaintSurface *surface)
{
- if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ &&
- surface->flags & MOD_DPAINT_ANTIALIAS)
- {
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ && surface->flags & MOD_DPAINT_ANTIALIAS) {
return (surface->data->total_points * 5);
}
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX &&
@@ -433,8 +420,10 @@ static int surface_totalSamples(DynamicPaintSurface *surface)
return surface->data->total_points;
}
-static void blendColors(const float t_color[3], float t_alpha, const float s_color[3], float s_alpha, float result[4])
+static void blendColors(
+ const float t_color[3], const float t_alpha, const float s_color[3], const float s_alpha, float result[4])
{
+ /* Same thing as BLI's blend_color_mix_float(), but for non-premultiplied alpha. */
int i;
float i_alpha = 1.0f - s_alpha;
float f_alpha = t_alpha * i_alpha + s_alpha;
@@ -507,15 +496,11 @@ static int surface_getBrushFlags(DynamicPaintSurface *surface, const Scene *scen
/* select object */
if (surface->brush_group) {
- if (go->ob) brushObj = go->ob;
+ if (go->ob)
+ brushObj = go->ob;
}
- else
+ else {
brushObj = base->object;
-
- if (!brushObj) {
- if (surface->brush_group) go = go->next;
- else base = base->next;
- continue;
}
if (surface->brush_group)
@@ -523,6 +508,10 @@ static int surface_getBrushFlags(DynamicPaintSurface *surface, const Scene *scen
else
base = base->next;
+ if (!brushObj) {
+ continue;
+ }
+
md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md;
@@ -539,56 +528,58 @@ static int surface_getBrushFlags(DynamicPaintSurface *surface, const Scene *scen
return flags;
}
-static int brush_usesMaterial(DynamicPaintBrushSettings *brush, Scene *scene)
+static int brush_usesMaterial(const DynamicPaintBrushSettings *brush, const Scene *scene)
{
return ((brush->flags & MOD_DPAINT_USE_MATERIAL) && (!BKE_scene_use_new_shading_nodes(scene)));
}
/* check whether two bounds intersect */
-static int boundsIntersect(Bounds3D *b1, Bounds3D *b2)
+static bool boundsIntersect(Bounds3D *b1, Bounds3D *b2)
{
- int i = 2;
- if (!b1->valid || !b2->valid) return 0;
- for (; i >= 0; i -= 1)
- if (!(b1->min[i] <= b2->max[i] && b1->max[i] >= b2->min[i])) return 0;
- return 1;
+ if (!b1->valid || !b2->valid)
+ return false;
+ for (int i = 2; i--;) {
+ if (!(b1->min[i] <= b2->max[i] && b1->max[i] >= b2->min[i]))
+ return false;
+ }
+ return true;
}
/* check whether two bounds intersect inside defined proximity */
-static int boundsIntersectDist(Bounds3D *b1, Bounds3D *b2, float dist)
+static bool boundsIntersectDist(Bounds3D *b1, Bounds3D *b2, const float dist)
{
- int i = 2;
- if (!b1->valid || !b2->valid) return 0;
- for (; i >= 0; i -= 1)
- if (!(b1->min[i] <= (b2->max[i] + dist) && b1->max[i] >= (b2->min[i] - dist))) return 0;
- return 1;
+ if (!b1->valid || !b2->valid)
+ return false;
+ for (int i = 2; i--;) {
+ if (!(b1->min[i] <= (b2->max[i] + dist) && b1->max[i] >= (b2->min[i] - dist)))
+ return false;
+ }
+ return true;
}
/* check whether bounds intersects a point with given radius */
-static int UNUSED_FUNCTION(boundIntersectPoint)(Bounds3D *b, float point[3], float radius)
+static bool UNUSED_FUNCTION(boundIntersectPoint)(Bounds3D *b, float point[3], const float radius)
{
- int i = 2;
- if (!b->valid) return 0;
- for (; i >= 0; i -= 1)
- if (!(b->min[i] <= (point[i] + radius) && b->max[i] >= (point[i] - radius))) return 0;
- return 1;
+ if (!b->valid)
+ return false;
+ for (int i = 2; i--;) {
+ if (!(b->min[i] <= (point[i] + radius) && b->max[i] >= (point[i] - radius)))
+ return false;
+ }
+ return true;
}
/* expand bounds by a new point */
static void boundInsert(Bounds3D *b, float point[3])
{
- int i = 2;
if (!b->valid) {
copy_v3_v3(b->min, point);
copy_v3_v3(b->max, point);
- b->valid = 1;
- }
- else {
- 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];
- }
+ b->valid = true;
+ return;
}
+
+ minmax_v3v3_v3(b->min, b->max, point);
}
static float getSurfaceDimension(PaintSurfaceData *sData)
@@ -611,65 +602,123 @@ static void freeGrid(PaintSurfaceData *data)
bData->grid = NULL;
}
+static void grid_bound_insert_cb_ex(void *userdata, void *userdata_chunk, const int i, const int UNUSED(thread_id))
+{
+ PaintBakeData *bData = userdata;
+
+ Bounds3D *grid_bound = userdata_chunk;
+
+ boundInsert(grid_bound, bData->realCoord[bData->s_pos[i]].v);
+}
+
+static void grid_bound_insert_finalize(void *userdata, void *userdata_chunk)
+{
+ PaintBakeData *bData = userdata;
+ VolumeGrid *grid = bData->grid;
+
+ Bounds3D *grid_bound = userdata_chunk;
+
+ boundInsert(&grid->grid_bounds, grid_bound->min);
+ boundInsert(&grid->grid_bounds, grid_bound->max);
+}
+
+static void grid_cell_points_cb_ex(void *userdata, void *userdata_chunk, const int i, const int UNUSED(thread_id))
+{
+ PaintBakeData *bData = userdata;
+ VolumeGrid *grid = bData->grid;
+ int *temp_t_index = grid->temp_t_index;
+ int *s_num = userdata_chunk;
+
+ int co[3];
+
+ for (int j = 3; j--;) {
+ co[j] = (int)floorf((bData->realCoord[bData->s_pos[i]].v[j] - grid->grid_bounds.min[j]) /
+ bData->dim[j] * grid->dim[j]);
+ CLAMP(co[j], 0, grid->dim[j] - 1);
+ }
+
+ temp_t_index[i] = co[0] + co[1] * grid->dim[0] + co[2] * grid->dim[0] * grid->dim[1];
+ s_num[temp_t_index[i]]++;
+}
+
+static void grid_cell_points_finalize(void *userdata, void *userdata_chunk)
+{
+ PaintBakeData *bData = userdata;
+ VolumeGrid *grid = bData->grid;
+ const int grid_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
+
+ int *s_num = userdata_chunk;
+
+ /* calculate grid indexes */
+ for (int i = 0; i < grid_cells; i++) {
+ grid->s_num[i] += s_num[i];
+ }
+}
+
+static void grid_cell_bounds_cb(void *userdata, const int x)
+{
+ PaintBakeData *bData = userdata;
+ VolumeGrid *grid = bData->grid;
+ float *dim = bData->dim;
+ int *grid_dim = grid->dim;
+
+ for (int y = 0; y < grid_dim[1]; y++) {
+ for (int z = 0; z < grid_dim[2]; z++) {
+ const int b_index = x + y * grid_dim[0] + z * grid_dim[0] * grid_dim[1];
+ /* set bounds */
+ for (int j = 3; j--;) {
+ const 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);
+ }
+ grid->bounds[b_index].valid = true;
+ }
+ }
+}
+
static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
{
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
- Bounds3D *grid_bounds;
VolumeGrid *grid;
int grid_cells, axis = 3;
int *temp_t_index = NULL;
int *temp_s_num = NULL;
-#ifdef _OPENMP
- int num_of_threads = omp_get_max_threads();
-#else
- int num_of_threads = 1;
-#endif
-
if (bData->grid)
freeGrid(sData);
- /* allocate separate bounds for each thread */
- grid_bounds = MEM_callocN(sizeof(Bounds3D) * num_of_threads, "Grid Bounds");
bData->grid = MEM_callocN(sizeof(VolumeGrid), "Surface Grid");
grid = bData->grid;
- if (grid && grid_bounds) {
+ {
int i, error = 0;
float dim_factor, volume, dim[3];
float td[3];
float min_dim;
/* calculate canvas dimensions */
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; i++) {
-#ifdef _OPENMP
- int id = omp_get_thread_num();
- boundInsert(&grid_bounds[id], (bData->realCoord[bData->s_pos[i]].v));
-#else
- boundInsert(&grid_bounds[0], (bData->realCoord[bData->s_pos[i]].v));
-#endif
- }
-
- /* get final dimensions */
- for (i = 0; i < num_of_threads; i++) {
- boundInsert(&grid->grid_bounds, grid_bounds[i].min);
- boundInsert(&grid->grid_bounds, grid_bounds[i].max);
- }
+ /* Important to init correctly our ref grid_bound... */
+ boundInsert(&grid->grid_bounds, bData->realCoord[bData->s_pos[0]].v);
+ BLI_task_parallel_range_finalize(
+ 0, sData->total_points, bData, &grid->grid_bounds, sizeof(grid->grid_bounds),
+ grid_bound_insert_cb_ex, grid_bound_insert_finalize, sData->total_points > 1000, false);
/* get dimensions */
sub_v3_v3v3(dim, grid->grid_bounds.max, grid->grid_bounds.min);
copy_v3_v3(td, dim);
+ copy_v3_v3(bData->dim, dim);
min_dim = max_fff(td[0], td[1], td[2]) / 1000.f;
/* deactivate zero axises */
for (i = 0; i < 3; i++) {
- if (td[i] < min_dim) { td[i] = 1.0f; axis -= 1; }
+ if (td[i] < min_dim) {
+ td[i] = 1.0f;
+ axis--;
+ }
}
if (axis == 0 || max_fff(td[0], td[1], td[2]) < 0.0001f) {
- MEM_freeN(grid_bounds);
MEM_freeN(bData->grid);
bData->grid = NULL;
return;
@@ -691,10 +740,11 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
/* allocate memory for grids */
grid->bounds = MEM_callocN(sizeof(Bounds3D) * grid_cells, "Surface Grid Bounds");
grid->s_pos = MEM_callocN(sizeof(int) * grid_cells, "Surface Grid Position");
- grid->s_num = MEM_callocN(sizeof(int) * grid_cells * num_of_threads, "Surface Grid Points");
+
+ grid->s_num = MEM_callocN(sizeof(int) * grid_cells, "Surface Grid Points");
temp_s_num = MEM_callocN(sizeof(int) * grid_cells, "Temp Surface Grid Points");
grid->t_index = MEM_callocN(sizeof(int) * sData->total_points, "Surface Grid Target Ids");
- temp_t_index = MEM_callocN(sizeof(int) * sData->total_points, "Temp Surface Grid Target Ids");
+ grid->temp_t_index = temp_t_index = MEM_callocN(sizeof(int) * sData->total_points, "Temp Surface Grid Target Ids");
/* in case of an allocation failure abort here */
if (!grid->bounds || !grid->s_pos || !grid->s_num || !grid->t_index || !temp_s_num || !temp_t_index)
@@ -702,33 +752,12 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
if (!error) {
/* calculate number of points withing each cell */
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; i++) {
- int co[3], j;
- 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);
- }
+ BLI_task_parallel_range_finalize(
+ 0, sData->total_points, bData, grid->s_num, sizeof(*grid->s_num) * grid_cells,
+ grid_cell_points_cb_ex, grid_cell_points_finalize, sData->total_points > 1000, false);
- temp_t_index[i] = co[0] + co[1] * grid->dim[0] + co[2] * grid->dim[0] * grid->dim[1];
-#ifdef _OPENMP
- grid->s_num[temp_t_index[i] + omp_get_thread_num() * grid_cells]++;
-#else
- grid->s_num[temp_t_index[i]]++;
-#endif
- }
-
- /* for first cell only calc s_num */
- for (i = 1; i < num_of_threads; i++) {
- grid->s_num[0] += grid->s_num[i * grid_cells];
- }
-
- /* calculate grid indexes */
+ /* calculate grid indexes (not needed for first cell, which is zero). */
for (i = 1; i < grid_cells; i++) {
- int id;
- for (id = 1; id < num_of_threads; id++) {
- grid->s_num[i] += grid->s_num[i + id * grid_cells];
- }
grid->s_pos[i] = grid->s_pos[i - 1] + grid->s_num[i - 1];
}
@@ -741,41 +770,20 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
}
/* calculate cell bounds */
- {
- int x;
-#pragma omp parallel for schedule(static)
- for (x = 0; x < grid->dim[0]; x++) {
- int y;
- for (y = 0; y < grid->dim[1]; y++) {
- int z;
- for (z = 0; z < grid->dim[2]; z++) {
- int j, b_index = x + y * grid->dim[0] + z * grid->dim[0] * grid->dim[1];
- /* set bounds */
- 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);
- }
- grid->bounds[b_index].valid = 1;
- }
- }
- }
- }
+ BLI_task_parallel_range(0, grid->dim[0], bData, grid_cell_bounds_cb, grid_cells > 1000);
}
- if (temp_s_num) MEM_freeN(temp_s_num);
- if (temp_t_index) MEM_freeN(temp_t_index);
-
- /* free per thread s_num values */
- grid->s_num = MEM_reallocN(grid->s_num, sizeof(int) * grid_cells);
+ if (temp_s_num)
+ MEM_freeN(temp_s_num);
+ if (temp_t_index)
+ MEM_freeN(temp_t_index);
+ grid->temp_t_index = NULL;
if (error || !grid->s_num) {
setError(surface->canvas, N_("Not enough free memory"));
freeGrid(sData);
}
}
-
- if (grid_bounds) MEM_freeN(grid_bounds);
}
/***************************** Freeing data ******************************/
@@ -790,10 +798,8 @@ void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd)
if (pmd->brush->paint_ramp)
MEM_freeN(pmd->brush->paint_ramp);
- pmd->brush->paint_ramp = NULL;
if (pmd->brush->vel_ramp)
MEM_freeN(pmd->brush->vel_ramp);
- pmd->brush->vel_ramp = NULL;
MEM_freeN(pmd->brush);
pmd->brush = NULL;
@@ -803,10 +809,14 @@ void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd)
static void dynamicPaint_freeAdjData(PaintSurfaceData *data)
{
if (data->adj_data) {
- if (data->adj_data->n_index) MEM_freeN(data->adj_data->n_index);
- if (data->adj_data->n_num) MEM_freeN(data->adj_data->n_num);
- if (data->adj_data->n_target) MEM_freeN(data->adj_data->n_target);
- if (data->adj_data->flags) MEM_freeN(data->adj_data->flags);
+ if (data->adj_data->n_index)
+ MEM_freeN(data->adj_data->n_index);
+ if (data->adj_data->n_num)
+ MEM_freeN(data->adj_data->n_num);
+ 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);
data->adj_data = NULL;
}
@@ -816,15 +826,24 @@ 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);
- if (bData->velocity) MEM_freeN(bData->velocity);
- if (bData->prev_velocity) MEM_freeN(bData->prev_velocity);
+ 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);
+ if (bData->velocity)
+ MEM_freeN(bData->velocity);
+ if (bData->prev_velocity)
+ MEM_freeN(bData->prev_velocity);
MEM_freeN(data->bData);
data->bData = NULL;
@@ -834,11 +853,11 @@ static void free_bakeData(PaintSurfaceData *data)
/* free surface data if it's not used anymore */
static void surface_freeUnusedData(DynamicPaintSurface *surface)
{
- if (!surface->data) return;
+ if (!surface->data)
+ return;
/* free bakedata if not active or surface is baked */
- if (!(surface->flags & MOD_DPAINT_ACTIVE))
- {
+ if (!(surface->flags & MOD_DPAINT_ACTIVE)) {
free_bakeData(surface->data);
}
}
@@ -846,7 +865,9 @@ static void surface_freeUnusedData(DynamicPaintSurface *surface)
void dynamicPaint_freeSurfaceData(DynamicPaintSurface *surface)
{
PaintSurfaceData *data = surface->data;
- if (!data) return;
+ if (!data)
+ return;
+
if (data->format_data) {
/* format specific free */
if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
@@ -859,7 +880,8 @@ void dynamicPaint_freeSurfaceData(DynamicPaintSurface *surface)
MEM_freeN(data->format_data);
}
/* type data */
- if (data->type_data) MEM_freeN(data->type_data);
+ if (data->type_data)
+ MEM_freeN(data->type_data);
dynamicPaint_freeAdjData(data);
/* bake data */
free_bakeData(data);
@@ -1022,7 +1044,7 @@ bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, str
brush->flags = MOD_DPAINT_ABS_ALPHA | MOD_DPAINT_RAMP_ALPHA;
brush->collision = MOD_DPAINT_COL_VOLUME;
-
+
brush->mat = NULL;
brush->r = 0.15f;
brush->g = 0.4f;
@@ -1210,31 +1232,24 @@ static void dynamicPaint_allocateSurfaceType(DynamicPaintSurface *surface)
break;
}
- if (sData->type_data == NULL) setError(surface->canvas, N_("Not enough free memory"));
+ if (sData->type_data == NULL)
+ setError(surface->canvas, N_("Not enough free memory"));
}
-static int surface_usesAdjDistance(DynamicPaintSurface *surface)
+static bool surface_usesAdjDistance(DynamicPaintSurface *surface)
{
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && surface->effect) return 1;
- if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) return 1;
- return 0;
+ return ((surface->type == MOD_DPAINT_SURFACE_T_PAINT && surface->effect) ||
+ (surface->type == MOD_DPAINT_SURFACE_T_WAVE));
}
-static int surface_usesAdjData(DynamicPaintSurface *surface)
+static bool surface_usesAdjData(DynamicPaintSurface *surface)
{
- if (surface_usesAdjDistance(surface)) return 1;
- if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX &&
- surface->flags & MOD_DPAINT_ANTIALIAS)
- {
- return 1;
- }
- else {
- return 0;
- }
+ return (surface_usesAdjDistance(surface) ||
+ (surface->format == MOD_DPAINT_SURFACE_F_VERTEX && surface->flags & MOD_DPAINT_ANTIALIAS));
}
/* initialize surface adjacency data */
-static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int force_init)
+static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, const bool force_init)
{
PaintSurfaceData *sData = surface->data;
DerivedMesh *dm = surface->canvas->dm;
@@ -1242,20 +1257,24 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int for
int *temp_data;
int neigh_points = 0;
- if (!surface_usesAdjData(surface) && !force_init) return;
+ if (!force_init && !surface_usesAdjData(surface))
+ return;
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
/* For vertex format, neighbors are connected by edges */
neigh_points = 2 * dm->getNumEdges(dm);
}
- else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
+ else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
neigh_points = sData->total_points * 8;
+ }
- if (!neigh_points) return;
+ if (!neigh_points)
+ return;
/* allocate memory */
ad = sData->adj_data = MEM_callocN(sizeof(PaintAdjData), "Surface Adj Data");
- if (!ad) return;
+ if (!ad)
+ return;
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");
@@ -1266,7 +1285,8 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int for
/* in case of allocation error, free memory */
if (!ad->n_index || !ad->n_num || !ad->n_target || !temp_data) {
dynamicPaint_freeAdjData(sData);
- if (temp_data) MEM_freeN(temp_data);
+ if (temp_data)
+ MEM_freeN(temp_data);
setError(surface->canvas, N_("Not enough free memory"));
return;
}
@@ -1294,8 +1314,7 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int for
/* also add number of vertices to temp_data
* to locate points on "mesh edge" */
for (i = 0; i < numOfPolys; i++) {
- int j = 0;
- for (; j < mpoly[i].totloop; j++) {
+ for (int j = 0; j < mpoly[i].totloop; j++) {
temp_data[mloop[mpoly[i].loopstart + j].v]++;
}
}
@@ -1303,13 +1322,11 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int for
/* now check if total number of edges+faces for
* each vertex is even, if not -> vertex is on mesh edge */
for (i = 0; i < sData->total_points; i++) {
- if ((temp_data[i] % 2) ||
- (temp_data[i] < 4))
- {
+ if ((temp_data[i] % 2) || (temp_data[i] < 4)) {
ad->flags[i] |= ADJ_ON_MESH_EDGE;
}
- /* reset temp data */
+ /* reset temp data */
temp_data[i] = 0;
}
@@ -1343,6 +1360,117 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int for
MEM_freeN(temp_data);
}
+typedef struct DynamicPaintSetInitColorData {
+ const DynamicPaintSurface *surface;
+
+ const MLoop *mloop;
+ const MLoopUV *mloopuv;
+ const MLoopTri *mlooptri;
+ const MLoopCol *mloopcol;
+ struct ImagePool *pool;
+
+ const bool scene_color_manage;
+} DynamicPaintSetInitColorData;
+
+static void dynamic_paint_set_init_color_tex_to_vcol_cb(void *userdata, const int i)
+{
+ const DynamicPaintSetInitColorData *data = userdata;
+
+ const PaintSurfaceData *sData = data->surface->data;
+ PaintPoint *pPoint = (PaintPoint *)sData->type_data;
+
+ const MLoop *mloop = data->mloop;
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
+ struct ImagePool *pool = data->pool;
+ Tex *tex = data->surface->init_texture;
+
+ const bool scene_color_manage = data->scene_color_manage;
+
+ float uv[3] = {0.0f};
+
+ for (int j = 3; j--;) {
+ TexResult texres = {0};
+ const unsigned int vert = mloop[mlooptri[i].tri[j]].v;
+
+ /* remap to [-1.0, 1.0] */
+ uv[0] = mloopuv[mlooptri[i].tri[j]].uv[0] * 2.0f - 1.0f;
+ uv[1] = mloopuv[mlooptri[i].tri[j]].uv[1] * 2.0f - 1.0f;
+
+ multitex_ext_safe(tex, uv, &texres, pool, scene_color_manage, false);
+
+ if (texres.tin > pPoint[vert].color[3]) {
+ copy_v3_v3(pPoint[vert].color, &texres.tr);
+ pPoint[vert].color[3] = texres.tin;
+ }
+ }
+}
+
+static void dynamic_paint_set_init_color_tex_to_imseq_cb(void *userdata, const int i)
+{
+ const DynamicPaintSetInitColorData *data = userdata;
+
+ const PaintSurfaceData *sData = data->surface->data;
+ PaintPoint *pPoint = (PaintPoint *)sData->type_data;
+
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
+ Tex *tex = data->surface->init_texture;
+ ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
+ const int samples = (data->surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+
+ const bool scene_color_manage = data->scene_color_manage;
+
+ float uv[9] = {0.0f};
+ float uv_final[3] = {0.0f};
+
+ TexResult texres = {0};
+
+ /* collect all uvs */
+ for (int j = 3; j--;) {
+ copy_v2_v2(&uv[j * 3], mloopuv[mlooptri[f_data->uv_p[i].tri_index].tri[j]].uv);
+ }
+
+ /* interpolate final uv pos */
+ interp_v3_v3v3v3(uv_final, &uv[0], &uv[3], &uv[6], f_data->barycentricWeights[i * samples].v);
+ /* remap to [-1.0, 1.0] */
+ uv_final[0] = uv_final[0] * 2.0f - 1.0f;
+ uv_final[1] = uv_final[1] * 2.0f - 1.0f;
+
+ multitex_ext_safe(tex, uv_final, &texres, NULL, scene_color_manage, false);
+
+ /* apply color */
+ copy_v3_v3(pPoint[i].color, &texres.tr);
+ pPoint[i].color[3] = texres.tin;
+}
+
+static void dynamic_paint_set_init_color_vcol_to_imseq_cb(void *userdata, const int i)
+{
+ const DynamicPaintSetInitColorData *data = userdata;
+
+ const PaintSurfaceData *sData = data->surface->data;
+ PaintPoint *pPoint = (PaintPoint *)sData->type_data;
+
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopCol *mloopcol = data->mloopcol;
+ ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
+ const int samples = (data->surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+
+ const int tri_idx = f_data->uv_p[i].tri_index;
+ float colors[3][4];
+ float final_color[4];
+
+ /* collect color values */
+ for (int j = 3; j--;) {
+ rgba_uchar_to_float(colors[j], (const unsigned char *)&mloopcol[mlooptri[tri_idx].tri[j]].r);
+ }
+
+ /* interpolate final color */
+ interp_v4_v4v4v4(final_color, UNPACK3(colors), f_data->barycentricWeights[i * samples].v);
+
+ copy_v4_v4(pPoint[i].color, final_color);
+}
+
static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface *surface)
{
PaintSurfaceData *sData = surface->data;
@@ -1356,10 +1484,10 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
if (surface->init_color_type == MOD_DPAINT_INITIAL_NONE)
return;
+
/* Single color */
- else if (surface->init_color_type == MOD_DPAINT_INITIAL_COLOR) {
+ if (surface->init_color_type == MOD_DPAINT_INITIAL_COLOR) {
/* apply color to every surface point */
-#pragma omp parallel for schedule(static)
for (i = 0; i < sData->total_points; i++) {
copy_v4_v4(pPoint[i].color, surface->init_color);
}
@@ -1375,69 +1503,36 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
char uvname[MAX_CUSTOMDATA_LAYER_NAME];
- if (!tex) return;
+ if (!tex)
+ return;
/* get uv map */
CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, surface->init_layername, uvname);
mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, uvname);
- if (!mloopuv) return;
+ if (!mloopuv)
+ return;
/* for vertex surface loop through tfaces and find uv color
* that provides highest alpha */
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
struct ImagePool *pool = BKE_image_pool_new();
-#pragma omp parallel for schedule(static) shared(pool)
- for (i = 0; i < tottri; i++) {
- float uv[3] = {0.0f};
- int j;
- for (j = 0; j < 3; j++) {
- TexResult texres = {0};
- unsigned int vert = mloop[mlooptri[i].tri[j]].v;
-
- /* remap to -1.0 to 1.0 */
- uv[0] = mloopuv[mlooptri[i].tri[j]].uv[0] * 2.0f - 1.0f;
- uv[1] = mloopuv[mlooptri[i].tri[j]].uv[1] * 2.0f - 1.0f;
-
- multitex_ext_safe(tex, uv, &texres, pool, scene_color_manage, false);
-
- if (texres.tin > pPoint[vert].color[3]) {
- copy_v3_v3(pPoint[vert].color, &texres.tr);
- pPoint[vert].color[3] = texres.tin;
- }
- }
- }
+ DynamicPaintSetInitColorData data = {
+ .surface = surface,
+ .mloop = mloop, .mlooptri = mlooptri, .mloopuv = mloopuv, .pool = pool,
+ .scene_color_manage = scene_color_manage
+ };
+ BLI_task_parallel_range(0, tottri, &data, dynamic_paint_set_init_color_tex_to_vcol_cb, tottri > 1000);
BKE_image_pool_free(pool);
}
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
- ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
- int samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
-
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; i++) {
- float uv[9] = {0.0f};
- float uv_final[3] = {0.0f};
- int j;
- TexResult texres = {0};
-
- /* collect all uvs */
- for (j = 0; j < 3; j++) {
- copy_v2_v2(&uv[j * 3], mloopuv[mlooptri[f_data->uv_p[i].tri_index].tri[j]].uv);
- }
-
- /* interpolate final uv pos */
- interp_v3_v3v3v3(uv_final, &uv[0], &uv[3], &uv[6],
- f_data->barycentricWeights[i * samples].v);
- /* remap to -1.0 to 1.0 */
- uv_final[0] = uv_final[0] * 2.0f - 1.0f;
- uv_final[1] = uv_final[1] * 2.0f - 1.0f;
-
- multitex_ext_safe(tex, uv_final, &texres, NULL, scene_color_manage, false);
-
- /* apply color */
- copy_v3_v3(pPoint[i].color, &texres.tr);
- pPoint[i].color[3] = texres.tin;
- }
+ DynamicPaintSetInitColorData data = {
+ .surface = surface,
+ .mlooptri = mlooptri, .mloopuv = mloopuv,
+ .scene_color_manage = scene_color_manage
+ };
+ BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_set_init_color_tex_to_imseq_cb,
+ sData->total_points > 1000);
}
}
/* vertex color layer */
@@ -1448,37 +1543,25 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
const MLoop *mloop = dm->getLoopArray(dm);
const int totloop = dm->getNumLoops(dm);
const MLoopCol *col = CustomData_get_layer_named(&dm->loopData, CD_MLOOPCOL, surface->init_layername);
- if (!col) return;
+ if (!col)
+ return;
-#pragma omp parallel for schedule(static)
for (i = 0; i < totloop; i++) {
rgba_uchar_to_float(pPoint[mloop[i].v].color, (const unsigned char *)&col[mloop[i].v].r);
}
}
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
const MLoopTri *mlooptri = dm->getLoopTriArray(dm);
- ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
- int samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
MLoopCol *col = CustomData_get_layer_named(&dm->loopData, CD_MLOOPCOL, surface->init_layername);
- if (!col) return;
-
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; i++) {
- int tri_ind = f_data->uv_p[i].tri_index;
- float colors[3][4];
- float final_color[4];
- int j;
-
- /* collect color values */
- for (j = 0; j < 3; j++) {
- rgba_uchar_to_float(colors[j], (const unsigned char *)&col[mlooptri[tri_ind].tri[j]].r);
- }
-
- /* interpolate final color */
- interp_v4_v4v4v4(final_color, UNPACK3(colors), f_data->barycentricWeights[i * samples].v);
-
- copy_v4_v4(pPoint[i].color, final_color);
- }
+ if (!col)
+ return;
+
+ DynamicPaintSetInitColorData data = {
+ .surface = surface,
+ .mlooptri = mlooptri, .mloopcol = col,
+ };
+ BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_set_init_color_vcol_to_imseq_cb,
+ sData->total_points > 1000);
}
}
}
@@ -1513,20 +1596,24 @@ bool dynamicPaint_resetSurface(const Scene *scene, DynamicPaintSurface *surface)
{
int numOfPoints = dynamicPaint_surfaceNumOfPoints(surface);
/* free existing data */
- if (surface->data) dynamicPaint_freeSurfaceData(surface);
+ if (surface->data)
+ dynamicPaint_freeSurfaceData(surface);
/* don't reallocate for image sequence types. they get handled only on bake */
- if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) return true;
- if (numOfPoints < 1) return false;
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
+ return true;
+ if (numOfPoints < 1)
+ return false;
/* allocate memory */
surface->data = MEM_callocN(sizeof(PaintSurfaceData), "PaintSurfaceData");
- if (!surface->data) return false;
+ if (!surface->data)
+ return false;
/* allocate data depending on surface type and format */
surface->data->total_points = numOfPoints;
dynamicPaint_allocateSurfaceType(surface);
- dynamicPaint_initAdjacencyData(surface, 0);
+ dynamicPaint_initAdjacencyData(surface, false);
/* set initial color */
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT)
@@ -1547,39 +1634,153 @@ static bool dynamicPaint_checkSurfaceData(const Scene *scene, DynamicPaintSurfac
/***************************** Modifier processing ******************************/
+typedef struct DynamicPaintModifierApplyData {
+ const DynamicPaintSurface *surface;
+ Object *ob;
+
+ MVert *mvert;
+ const MLoop *mloop;
+ const MPoly *mpoly;
+
+ float (*fcolor)[4];
+ MLoopCol *mloopcol;
+ MLoopCol *mloopcol_wet;
+ MLoopCol *mloopcol_preview;
+} DynamicPaintModifierApplyData;
+
+static void dynamic_paint_apply_surface_displace_cb(void *userdata, const int i)
+{
+ const DynamicPaintModifierApplyData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ MVert *mvert = data->mvert;
+
+ float normal[3];
+ const float *value = (float *)surface->data->type_data;
+ const float val = value[i] * surface->disp_factor;
+
+ normal_short_to_float_v3(normal, mvert[i].no);
+
+ /* same as 'mvert[i].co[0] -= normal[0] * val' etc. */
+ madd_v3_v3fl(mvert[i].co, normal, -val);
+}
/* apply displacing vertex surface to the derived mesh */
static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, DerivedMesh *result)
{
PaintSurfaceData *sData = surface->data;
- if (!sData || surface->format != MOD_DPAINT_SURFACE_F_VERTEX) return;
+ if (!sData || surface->format != MOD_DPAINT_SURFACE_F_VERTEX)
+ return;
/* displace paint */
if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
MVert *mvert = result->getVertArray(result);
- int i;
- const float *value = (float *)sData->type_data;
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; i++) {
- float normal[3], val = value[i] * surface->disp_factor;
- normal_short_to_float_v3(normal, mvert[i].no);
- normalize_v3(normal);
+ DynamicPaintModifierApplyData data = {.surface = surface, .mvert = mvert};
+ BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_apply_surface_displace_cb,
+ sData->total_points > 10000);
+ }
+}
+
+static void dynamic_paint_apply_surface_vpaint_blend_cb(void *userdata, const int i)
+{
+ const DynamicPaintModifierApplyData *data = userdata;
+
+ PaintPoint *pPoint = (PaintPoint *)data->surface->data->type_data;
+ float (*fcolor)[4] = data->fcolor;
+
+ /* blend dry and wet layer */
+ blendColors(pPoint[i].color, pPoint[i].color[3], pPoint[i].e_color, pPoint[i].e_color[3], fcolor[i]);
+}
+
+static void dynamic_paint_apply_surface_vpaint_cb(void *userdata, const int p_index)
+{
+ const DynamicPaintModifierApplyData *data = userdata;
+ Object *ob = data->ob;
+
+ const MLoop *mloop = data->mloop;
+ const MPoly *mpoly = data->mpoly;
- mvert[i].co[0] -= normal[0] * val;
- mvert[i].co[1] -= normal[1] * val;
- mvert[i].co[2] -= normal[2] * val;
+ const DynamicPaintSurface *surface = data->surface;
+ PaintPoint *pPoint = (PaintPoint *)surface->data->type_data;
+ float (*fcolor)[4] = data->fcolor;
+
+ MLoopCol *mloopcol = data->mloopcol;
+ MLoopCol *mloopcol_wet = data->mloopcol_wet;
+ MLoopCol *mloopcol_preview = data->mloopcol_preview;
+
+ const Material *material = mloopcol_preview ?
+ give_current_material(ob, mpoly[p_index].mat_nr + 1) : NULL;
+
+ for (int j = 0; j < mpoly[p_index].totloop; j++) {
+ const int l_index = mpoly[p_index].loopstart + j;
+ const int v_index = mloop[l_index].v;
+
+ /* save layer data to output layer */
+ /* apply color */
+ if (mloopcol) {
+ rgba_float_to_uchar((unsigned char *)&mloopcol[l_index].r, fcolor[v_index]);
+ }
+ /* apply wetness */
+ if (mloopcol_wet) {
+ const char c = FTOCHAR(pPoint[v_index].wetness);
+ mloopcol_wet[l_index].r = c;
+ mloopcol_wet[l_index].g = c;
+ mloopcol_wet[l_index].b = c;
+ mloopcol_wet[l_index].a = 255;
+ }
+
+ /* viewport preview */
+ if (mloopcol_preview) {
+ if (surface->preview_id == MOD_DPAINT_SURFACE_PREV_PAINT) {
+ float c[3];
+
+ /* Apply material color as base vertex color for preview */
+ mloopcol_preview[l_index].a = 255;
+ if (material) {
+ c[0] = material->r;
+ c[1] = material->g;
+ c[2] = material->b;
+ }
+ else { /* default gray */
+ c[0] = 0.65f;
+ c[1] = 0.65f;
+ c[2] = 0.65f;
+ }
+ /* mix surface color */
+ interp_v3_v3v3(c, c, fcolor[v_index], fcolor[v_index][3]);
+
+ rgb_float_to_uchar((unsigned char *)&mloopcol_preview[l_index].r, c);
+ }
+ else {
+ const char c = FTOCHAR(pPoint[v_index].wetness);
+ mloopcol_preview[l_index].r = c;
+ mloopcol_preview[l_index].g = c;
+ mloopcol_preview[l_index].b = c;
+ mloopcol_preview[l_index].a = 255;
+ }
}
}
}
+static void dynamic_paint_apply_surface_wave_cb(void *userdata, const int i)
+{
+ const DynamicPaintModifierApplyData *data = userdata;
+
+ PaintWavePoint *wPoint = (PaintWavePoint *)data->surface->data->type_data;
+ MVert *mvert = data->mvert;
+ float normal[3];
+
+ normal_short_to_float_v3(normal, mvert[i].no);
+ madd_v3_v3fl(mvert[i].co, normal, wPoint[i].height);
+}
+
/*
* Apply canvas data to the object derived mesh
*/
-static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd,
- Object *ob,
- DerivedMesh *dm)
+static DerivedMesh *dynamicPaint_Modifier_apply(
+ DynamicPaintModifierData *pmd, Object *ob, DerivedMesh *dm)
{
DerivedMesh *result = CDDM_copy(dm);
@@ -1593,129 +1794,65 @@ static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd,
PaintSurfaceData *sData = surface->data;
if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ && sData) {
- if (!(surface->flags & (MOD_DPAINT_ACTIVE))) continue;
+ 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) {
-
- int i;
- PaintPoint *pPoint = (PaintPoint *)sData->type_data;
- MLoopCol *col = NULL;
MLoop *mloop = CDDM_get_loops(result);
- int totloop = result->numLoopData;
+ const int totloop = result->numLoopData;
+ MPoly *mpoly = CDDM_get_polys(result);
+ const int totpoly = result->numPolyData;
/* paint is stored on dry and wet layers, so mix final color first */
- float *fcolor = MEM_callocN(sizeof(float) * sData->total_points * 4, "Temp paint color");
-
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; i++) {
- /* blend dry and wet layer */
- blendColors(pPoint[i].color, pPoint[i].color[3], pPoint[i].e_color, pPoint[i].e_color[3], &fcolor[i * 4]);
- }
-
- /* viewport preview */
- if (surface->flags & MOD_DPAINT_PREVIEW) {
- MPoly *mp = CDDM_get_polys(result);
- int totpoly = result->numPolyData;
-
-#if 0
- /* XXX We have to create a CD_PREVIEW_MCOL, else it might sigsev
- * (after a SubSurf mod, eg)... */
- if (!result->getTessFaceDataArray(result, CD_PREVIEW_MCOL)) {
- int numFaces = result->getNumTessFaces(result);
- CustomData_add_layer(&result->faceData, CD_PREVIEW_MCOL, CD_CALLOC, NULL, numFaces);
- }
-#endif
-
- /* Save preview results to weight layer to be
- * able to share same drawing methods */
- col = CustomData_get_layer(&result->loopData, CD_PREVIEW_MLOOPCOL);
- if (!col)
- col = CustomData_add_layer(&result->loopData, CD_PREVIEW_MLOOPCOL, CD_CALLOC,
- NULL, totloop);
-
- if (col) {
-#pragma omp parallel for schedule(static)
- for (i = 0; i < totpoly; i++) {
- int j = 0;
- Material *material = give_current_material(ob, mp[i].mat_nr + 1);
-
- for (; j < mp[i].totloop; j++) {
- int l_index = mp[i].loopstart + j;
- int v_index = mloop[l_index].v;
-
- if (surface->preview_id == MOD_DPAINT_SURFACE_PREV_PAINT) {
- float c[3];
- v_index *= 4;
-
- /* Apply material color as base vertex color for preview */
- col[l_index].a = 255;
- if (material) {
- c[0] = material->r;
- c[1] = material->g;
- c[2] = material->b;
- }
- else { /* default gray */
- c[0] = 0.65f;
- c[1] = 0.65f;
- c[2] = 0.65f;
- }
- /* mix surface color */
- interp_v3_v3v3(c, c, &fcolor[v_index], fcolor[v_index + 3]);
-
- rgb_float_to_uchar((unsigned char *)&col[l_index].r, c);
- }
- else {
- col[l_index].r =
- col[l_index].g =
- col[l_index].b = FTOCHAR(pPoint[v_index].wetness);
- col[l_index].a = 255;
- }
- }
- }
- }
- }
+ float (*fcolor)[4] = MEM_callocN(sizeof(*fcolor) * sData->total_points, "Temp paint color");
-
- /* save layer data to output layer */
+ DynamicPaintModifierApplyData data = {.surface = surface, .fcolor = fcolor};
+ BLI_task_parallel_range(0, sData->total_points, &data,
+ dynamic_paint_apply_surface_vpaint_blend_cb,
+ sData->total_points > 1000);
/* paint layer */
- col = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name);
+ MLoopCol *mloopcol = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name);
/* if output layer is lost from a constructive modifier, re-add it */
- if (!col && dynamicPaint_outputLayerExists(surface, ob, 0))
- col = CustomData_add_layer_named(&result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name);
- /* apply color */
- if (col) {
-#pragma omp parallel for schedule(static)
- for (i = 0; i < totloop; i++) {
- int index = mloop[i].v * 4;
- rgb_float_to_uchar((unsigned char *)&col[i].r, &fcolor[index]);
- col[i].a = FTOCHAR(fcolor[index + 3]); /* IS THIS NEEDED? */
- }
+ if (!mloopcol && dynamicPaint_outputLayerExists(surface, ob, 0)) {
+ mloopcol = CustomData_add_layer_named(
+ &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name);
}
-
- MEM_freeN(fcolor);
/* wet layer */
- col = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name2);
+ MLoopCol *mloopcol_wet = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name2);
/* if output layer is lost from a constructive modifier, re-add it */
- if (!col && dynamicPaint_outputLayerExists(surface, ob, 1))
- col = CustomData_add_layer_named(&result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2);
- /* apply color */
- if (col) {
-#pragma omp parallel for schedule(static)
- for (i = 0; i < totloop; i++) {
- int index = mloop[i].v;
- col[i].r =
- col[i].g =
- col[i].b = FTOCHAR(pPoint[index].wetness);
- col[i].a = 255;
+ if (!mloopcol_wet && dynamicPaint_outputLayerExists(surface, ob, 1)) {
+ mloopcol_wet = CustomData_add_layer_named(
+ &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2);
+ }
+
+ /* Save preview results to weight layer to be able to share same drawing methods */
+ MLoopCol *mloopcol_preview = NULL;
+ if (surface->flags & MOD_DPAINT_PREVIEW) {
+ mloopcol_preview = CustomData_get_layer(&result->loopData, CD_PREVIEW_MLOOPCOL);
+ if (!mloopcol_preview) {
+ mloopcol_preview = CustomData_add_layer(
+ &result->loopData, CD_PREVIEW_MLOOPCOL, CD_CALLOC, NULL, totloop);
}
}
+ data.ob = ob;
+ data.mloop = mloop;
+ data.mpoly = mpoly;
+ data.mloopcol = mloopcol;
+ data.mloopcol_wet = mloopcol_wet;
+ data.mloopcol_preview = mloopcol_preview;
+
+ BLI_task_parallel_range(0, totpoly, &data, dynamic_paint_apply_surface_vpaint_cb,
+ totpoly > 1000);
+
+ MEM_freeN(fcolor);
+
/* Mark tessellated CD layers as dirty. */
result->dirty |= DM_DIRTY_TESS_CDLAYERS;
}
@@ -1734,9 +1871,10 @@ static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd,
}
/* apply weights into a vertex group, if doesnt exists add a new layer */
- if (defgrp_index != -1 && !dvert && (surface->output_name[0] != '\0'))
+ if (defgrp_index != -1 && !dvert && (surface->output_name[0] != '\0')) {
dvert = CustomData_add_layer_named(&result->vertData, CD_MDEFORMVERT, CD_CALLOC,
NULL, sData->total_points, surface->output_name);
+ }
if (defgrp_index != -1 && dvert) {
int i;
for (i = 0; i < sData->total_points; i++) {
@@ -1745,7 +1883,6 @@ static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd,
/* skip if weight value is 0 and no existing weight is found */
if ((def_weight != NULL) || (weight[i] != 0.0f)) {
-
/* if not found, add a weight for it */
if (def_weight == NULL) {
def_weight = defvert_verify_index(dv, defgrp_index);
@@ -1760,15 +1897,10 @@ static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd,
/* wave simulation */
else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
MVert *mvert = result->getVertArray(result);
- int i;
- PaintWavePoint *wPoint = (PaintWavePoint *)sData->type_data;
-
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; i++) {
- float normal[3];
- normal_short_to_float_v3(normal, mvert[i].no);
- madd_v3_v3fl(mvert[i].co, normal, wPoint[i].height);
- }
+
+ DynamicPaintModifierApplyData data = {.surface = surface, .mvert = mvert};
+ BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_apply_surface_wave_cb,
+ sData->total_points > 1000);
update_normals = true;
}
@@ -1787,7 +1919,8 @@ static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd,
}
/* make a copy of dm to use as brush data */
if (pmd->brush) {
- if (pmd->brush->dm) pmd->brush->dm->release(pmd->brush->dm);
+ if (pmd->brush->dm)
+ pmd->brush->dm->release(pmd->brush->dm);
pmd->brush->dm = CDDM_copy(result);
}
@@ -1816,7 +1949,8 @@ static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, Scene *scene
canvas_copyDerivedMesh(canvas, dm);
/* in case image sequence baking, stop here */
- if (canvas->flags & MOD_DPAINT_BAKING) return;
+ if (canvas->flags & MOD_DPAINT_BAKING)
+ return;
/* loop through surfaces */
for (; surface; surface = surface->next) {
@@ -1827,17 +1961,20 @@ static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, Scene *scene
surface_freeUnusedData(surface);
/* image sequences are handled by bake operator */
- if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) continue;
- if (!(surface->flags & MOD_DPAINT_ACTIVE)) continue;
+ if ((surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) || !(surface->flags & MOD_DPAINT_ACTIVE))
+ continue;
/* make sure surface is valid */
no_surface_data = surface->data == NULL;
- if (!dynamicPaint_checkSurfaceData(scene, surface)) continue;
+ if (!dynamicPaint_checkSurfaceData(scene, surface))
+ continue;
/* limit frame range */
CLAMP(current_frame, surface->start_frame, surface->end_frame);
- if (no_surface_data || current_frame != surface->current_frame || (int)scene->r.cfra == surface->start_frame) {
+ if (no_surface_data || current_frame != surface->current_frame ||
+ (int)scene->r.cfra == surface->start_frame)
+ {
surface->current_frame = current_frame;
/* if we're on surface range do recalculate */
@@ -1862,263 +1999,462 @@ static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, Scene *scene
/* Modifier call. Processes dynamic paint modifier step. */
DerivedMesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm)
{
- /* For now generate looptris in every case */
- DM_ensure_looptri(dm);
+ if (pmd->canvas) {
+ DerivedMesh *ret;
+
+ /* For now generate looptris in every case */
+ DM_ensure_looptri(dm);
- /* Update canvas data for a new frame */
- dynamicPaint_frameUpdate(pmd, scene, ob, dm);
+ /* Update canvas data for a new frame */
+ dynamicPaint_frameUpdate(pmd, scene, ob, dm);
+
+ /* Return output mesh */
+ ret = dynamicPaint_Modifier_apply(pmd, ob, dm);
+
+ return ret;
+ }
+ else {
+ /* For now generate looptris in every case */
+ DM_ensure_looptri(dm);
- /* Return output mesh */
- return dynamicPaint_Modifier_apply(pmd, ob, dm);
+ /* Update canvas data for a new frame */
+ dynamicPaint_frameUpdate(pmd, scene, ob, dm);
+
+ /* Return output mesh */
+ return dynamicPaint_Modifier_apply(pmd, ob, dm);
+ }
}
/***************************** Image Sequence / UV Image Surface Calls ******************************/
/*
- * Tries to find the neighboring pixel in given (uv space) direction.
- * Result is used by effect system to move paint on the surface.
+ * Create a surface for uv image sequence format
+ */
+#define JITTER_SAMPLES { \
+ 0.0f, 0.0f, \
+ -0.2f, -0.4f, \
+ 0.2f, 0.4f, \
+ 0.4f, -0.2f, \
+ -0.4f, 0.3f, \
+}
+
+typedef struct DynamicPaintCreateUVSurfaceData {
+ const DynamicPaintSurface *surface;
+
+ PaintUVPoint *tempPoints;
+ Vec3f *tempWeights;
+
+ const MLoopTri *mlooptri;
+ const MLoopUV *mloopuv;
+ const MLoop *mloop;
+ const int tottri;
+
+ const Bounds2D *faceBB;
+ uint32_t *active_points;
+} DynamicPaintCreateUVSurfaceData;
+
+static void dynamic_paint_create_uv_surface_direct_cb(void *userdata, const int ty)
+{
+ const DynamicPaintCreateUVSurfaceData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ PaintUVPoint *tempPoints = data->tempPoints;
+ Vec3f *tempWeights = data->tempWeights;
+
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
+ const MLoop *mloop = data->mloop;
+ const int tottri = data->tottri;
+
+ const Bounds2D *faceBB = data->faceBB;
+
+ const float jitter5sample[10] = JITTER_SAMPLES;
+ const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+ const int w = surface->image_resolution;
+ const int h = w;
+
+ for (int tx = 0; tx < w; tx++) {
+ const int index = tx + w * ty;
+ PaintUVPoint *tPoint = &tempPoints[index];
+ float point[5][2];
+
+ /* Init per pixel settings */
+ tPoint->tri_index = -1;
+ tPoint->neighbour_pixel = -1;
+ tPoint->pixel_index = index;
+
+ /* Actual pixel center, used when collision is found */
+ point[0][0] = ((float)tx + 0.5f) / w;
+ point[0][1] = ((float)ty + 0.5f) / h;
+
+ /*
+ * A pixel middle sample isn't enough to find very narrow polygons
+ * So using 4 samples of each corner too
+ */
+ point[1][0] = ((float)tx) / w;
+ point[1][1] = ((float)ty) / h;
+
+ point[2][0] = ((float)tx + 1) / w;
+ point[2][1] = ((float)ty) / h;
+
+ point[3][0] = ((float)tx) / w;
+ point[3][1] = ((float)ty + 1) / h;
+
+ point[4][0] = ((float)tx + 1) / w;
+ point[4][1] = ((float)ty + 1) / h;
+
+
+ /* Loop through samples, starting from middle point */
+ for (int sample = 0; sample < 5; sample++) {
+ /* Loop through every face in the mesh */
+ /* XXX TODO This is *horrible* with big meshes, should use a 2D BVHTree over UV tris here! */
+ for (int i = 0; i < tottri; i++) {
+ /* Check uv bb */
+ if ((faceBB[i].min[0] > point[sample][0]) ||
+ (faceBB[i].min[1] > point[sample][1]) ||
+ (faceBB[i].max[0] < point[sample][0]) ||
+ (faceBB[i].max[1] < point[sample][1]))
+ {
+ continue;
+ }
+
+ const float *uv1 = mloopuv[mlooptri[i].tri[0]].uv;
+ const float *uv2 = mloopuv[mlooptri[i].tri[1]].uv;
+ const float *uv3 = mloopuv[mlooptri[i].tri[2]].uv;
+
+ /* If point is inside the face */
+ if (isect_point_tri_v2(point[sample], uv1, uv2, uv3) != 0) {
+ float uv[2];
+
+ /* Add b-weights per anti-aliasing sample */
+ for (int 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;
+
+ barycentric_weights_v2(uv1, uv2, uv3, uv, tempWeights[index * aa_samples + j].v);
+ }
+
+ /* Set surface point face values */
+ tPoint->tri_index = i;
+
+ /* save vertex indexes */
+ tPoint->v1 = mloop[mlooptri[i].tri[0]].v;
+ tPoint->v2 = mloop[mlooptri[i].tri[1]].v;
+ tPoint->v3 = mloop[mlooptri[i].tri[2]].v;
+
+ sample = 5; /* make sure we exit sample loop as well */
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const int ty)
+{
+ const DynamicPaintCreateUVSurfaceData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ PaintUVPoint *tempPoints = data->tempPoints;
+ Vec3f *tempWeights = data->tempWeights;
+
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
+ const MLoop *mloop = data->mloop;
+
+ uint32_t *active_points = data->active_points;
+
+ const float jitter5sample[10] = JITTER_SAMPLES;
+ const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+ const int w = surface->image_resolution;
+ const int h = w;
+
+ for (int tx = 0; tx < w; tx++) {
+ const int index = tx + w * ty;
+ PaintUVPoint *tPoint = &tempPoints[index];
+
+ /* If point isn't on canvas mesh */
+ if (tPoint->tri_index == -1) {
+ float point[2];
+
+ /* get loop area */
+ const int u_min = (tx > 0) ? -1 : 0;
+ const int u_max = (tx < (w - 1)) ? 1 : 0;
+ const int v_min = (ty > 0) ? -1 : 0;
+ const int v_max = (ty < (h - 1)) ? 1 : 0;
+
+ point[0] = ((float)tx + 0.5f) / w;
+ point[1] = ((float)ty + 0.5f) / h;
+
+ /* search through defined area for neighbor */
+ for (int u = u_min; u <= u_max; u++) {
+ for (int v = v_min; v <= v_max; v++) {
+ /* if not this pixel itself */
+ if (u != 0 || v != 0) {
+ const int ind = (tx + u) + w * (ty + v);
+
+ /* if neighbor has index */
+ if (tempPoints[ind].neighbour_pixel == -1 && tempPoints[ind].tri_index != -1) {
+ float uv[2];
+ const int i = tempPoints[ind].tri_index;
+ const float *uv1 = mloopuv[mlooptri[i].tri[0]].uv;
+ const float *uv2 = mloopuv[mlooptri[i].tri[1]].uv;
+ const float *uv3 = mloopuv[mlooptri[i].tri[2]].uv;
+
+ /* tri index */
+ /* There is a low possibility of actually having a neighbor point which tri is
+ * already set from another neighbor in a separate thread here.
+ * Cheking for both tri_index and neighbour_pixel above reduces that probability
+ * but it remains possible.
+ * That atomic op (and its memory fence) ensures tPoint->neighbour_pixel is set
+ * to non--1 *before* its tri_index is set (i.e. that it cannot be used a neighbour).
+ */
+ tPoint->neighbour_pixel = ind - 1;
+ atomic_add_uint32(&tPoint->neighbour_pixel, 1);
+ tPoint->tri_index = i;
+
+ /* Now calculate pixel data for this pixel as it was on polygon surface */
+ /* Add b-weights per anti-aliasing sample */
+ for (int j = 0; j < aa_samples; j++) {
+ uv[0] = point[0] + jitter5sample[j * 2] / w;
+ uv[1] = point[1] + jitter5sample[j * 2 + 1] / h;
+ barycentric_weights_v2(uv1, uv2, uv3, uv, tempWeights[index * aa_samples + j].v);
+ }
+
+ /* save vertex indexes */
+ tPoint->v1 = mloop[mlooptri[i].tri[0]].v;
+ tPoint->v2 = mloop[mlooptri[i].tri[1]].v;
+ tPoint->v3 = mloop[mlooptri[i].tri[2]].v;
+
+ u = u_max + 1; /* make sure we exit outer loop as well */
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* Increase the final number of active surface points if relevant. */
+ if (tPoint->tri_index != -1)
+ atomic_add_uint32(active_points, 1);
+ }
+}
+
+#undef JITTER_SAMPLES
+
+/* 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)
+ * px, py : origin pixel x and y
+ * n_index : lookup direction index (use neighX, neighY to get final index)
*/
-static int dynamicPaint_findNeighbourPixel(PaintUVPoint *tempPoints, DerivedMesh *dm,
- const char *uvname, int w, int h, int px, int py, int n_index)
+static int dynamic_paint_find_neighbour_pixel(
+ const DynamicPaintCreateUVSurfaceData *data, const MeshElemMap *vert_to_looptri_map,
+ const int w, const int h, const int px, const int py, const int n_index)
{
/* Note: Current method only uses polygon edges to detect neighboring pixels.
- * -> It doesn't always lead to the optimum pixel but is accurate enough
- * and faster/simpler than including possible face tip point links)
+ * -> It doesn't always lead to the optimum pixel but is accurate enough
+ * and faster/simpler than including possible face tip point links)
*/
- int x, y;
- PaintUVPoint *tPoint = NULL;
- PaintUVPoint *cPoint = NULL;
-
/* shift position by given n_index */
- x = px + neighX[n_index];
- y = py + neighY[n_index];
+ const int x = px + neighX[n_index];
+ const int y = py + neighY[n_index];
- if (x < 0 || x >= w) return OUT_OF_TEXTURE;
- if (y < 0 || y >= h) return OUT_OF_TEXTURE;
+ if (x < 0 || x >= w || y < 0 || y >= h)
+ return OUT_OF_TEXTURE;
- tPoint = &tempPoints[x + w * y]; /* UV neighbor */
- cPoint = &tempPoints[px + w * py]; /* Origin point */
+ const PaintUVPoint *tempPoints = data->tempPoints;
+ const PaintUVPoint *tPoint = &tempPoints[x + w * y]; /* UV neighbor */
+ const PaintUVPoint *cPoint = &tempPoints[px + w * py]; /* Origin point */
- /*
- * Check if shifted point is on same face -> it's a correct neighbor
- * (and if it isn't marked as an "edge pixel")
- */
+ /* Check if shifted point is on same face -> it's a correct neighbor (and if it isn't marked as an "edge pixel") */
if ((tPoint->tri_index == cPoint->tri_index) && (tPoint->neighbour_pixel == -1))
return (x + w * y);
- /*
- * Even if shifted point is on another face
- * -> use this point.
+ /* Even if shifted point is on another face
+ * -> use this point.
*
- * !! Replace with "is uv faces linked" check !!
- * This should work fine as long as uv island
- * margin is > 1 pixel.
+ * !! Replace with "is uv faces linked" check !!
+ * This should work fine as long as uv island margin is > 1 pixel.
*/
if ((tPoint->tri_index != -1) && (tPoint->neighbour_pixel == -1)) {
return (x + w * y);
}
- /*
- * 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.
+ /* If we get here, the actual neighboring pixel is located on a non-linked uv face,
+ * and we have to find its "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
+ * 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?
+ * TODO: Implement something more accurate / optimized?
*/
{
- const MLoop *mloop = dm->getLoopArray(dm);
- const MLoopTri *mlooptri = dm->getLoopTriArray(dm);
- const int tottri = dm->getNumLoopTri(dm);
- const MLoopUV *mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, uvname);
+ const MLoop *mloop = data->mloop;
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
/* Get closest edge to that subpixel on UV map */
- {
- float pixel[2];
- /* distances only used for comparison */
- float dist_squared, t_dist_squared;
-
- int i, edge1_index, edge2_index,
- e1_index, e2_index, target_tri;
- float closest_point[2], lambda, dir_vec[2];
- int target_uv1 = 0, target_uv2 = 0, final_pixel[2], final_index;
-
- const float *s_uv1, *s_uv2, *t_uv1, *t_uv2;
-
- pixel[0] = ((float)(px + neighX[n_index]) + 0.5f) / (float)w;
- pixel[1] = ((float)(py + neighY[n_index]) + 0.5f) / (float)h;
-
- /*
- * Find closest edge to that pixel
- */
-
- /* Dist to first edge */
- e1_index = cPoint->v1;
- e2_index = cPoint->v2;
- edge1_index = 0;
- edge2_index = 1;
- dist_squared = dist_squared_to_line_segment_v2(
- pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv);
-
- /* Dist to second edge */
- t_dist_squared = dist_squared_to_line_segment_v2(
- pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv);
- if (t_dist_squared < dist_squared) {
- e1_index = cPoint->v2;
- e2_index = cPoint->v3;
- edge1_index = 1;
- edge2_index = 2;
- dist_squared = t_dist_squared;
- }
- /* Dist to third edge */
- t_dist_squared = dist_squared_to_line_segment_v2(
- pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv);
- if (t_dist_squared < dist_squared) {
- e1_index = cPoint->v3;
- e2_index = cPoint->v1;
- edge1_index = 2;
- edge2_index = 0;
- dist_squared = t_dist_squared;
- }
+ float pixel[2];
+ /* distances only used for comparison */
+ float dist_squared, t_dist_squared;
+ int edge1_index, edge2_index;
+ int e1_index, e2_index, target_tri;
+ float closest_point[2], lambda, dir_vec[2];
+ int target_uv1 = 0, target_uv2 = 0, final_pixel[2], final_index;
- /*
- * Now find another face that is linked to that edge
- */
- target_tri = -1;
+ const float *s_uv1, *s_uv2, *t_uv1, *t_uv2;
- for (i = 0; i < tottri; i++) {
- /*
- * Check if both edge vertices share this face
- */
- if ((e1_index == mloop[mlooptri[i].tri[0]].v || e1_index == mloop[mlooptri[i].tri[1]].v || e1_index == mloop[mlooptri[i].tri[2]].v) &&
- (e2_index == mloop[mlooptri[i].tri[0]].v || e2_index == mloop[mlooptri[i].tri[1]].v || e2_index == mloop[mlooptri[i].tri[2]].v))
- {
- if (i == cPoint->tri_index) continue;
+ pixel[0] = ((float)(px + neighX[n_index]) + 0.5f) / (float)w;
+ pixel[1] = ((float)(py + neighY[n_index]) + 0.5f) / (float)h;
- target_tri = i;
+ /*
+ * Find closest edge to that pixel
+ */
- /*
- * Get edge UV index
- */
- if (e1_index == mloop[mlooptri[i].tri[0]].v) target_uv1 = 0;
- else if (e1_index == mloop[mlooptri[i].tri[1]].v) target_uv1 = 1;
- else if (e1_index == mloop[mlooptri[i].tri[2]].v) target_uv1 = 2;
+ /* Dist to first edge */
+ e1_index = cPoint->v1;
+ e2_index = cPoint->v2;
+ edge1_index = 0;
+ edge2_index = 1;
+ dist_squared = dist_squared_to_line_segment_v2(
+ pixel,
+ mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv,
+ mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv);
+
+ /* Dist to second edge */
+ t_dist_squared = dist_squared_to_line_segment_v2(
+ pixel,
+ mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv,
+ mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv);
+ if (t_dist_squared < dist_squared) {
+ e1_index = cPoint->v2;
+ e2_index = cPoint->v3;
+ edge1_index = 1;
+ edge2_index = 2;
+ dist_squared = t_dist_squared;
+ }
- if (e2_index == mloop[mlooptri[i].tri[0]].v) target_uv2 = 0;
- else if (e2_index == mloop[mlooptri[i].tri[1]].v) target_uv2 = 1;
- else if (e2_index == mloop[mlooptri[i].tri[2]].v) target_uv2 = 2;
+ /* Dist to third edge */
+ t_dist_squared = dist_squared_to_line_segment_v2(
+ pixel,
+ mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv,
+ mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv);
+ if (t_dist_squared < dist_squared) {
+ e1_index = cPoint->v3;
+ e2_index = cPoint->v1;
+ edge1_index = 2;
+ edge2_index = 0;
+ dist_squared = t_dist_squared;
+ }
- break;
- }
- }
+ /*
+ * Now find another face that is linked to that edge
+ */
+ target_tri = -1;
- /* If none found pixel is on mesh edge */
- if (target_tri == -1) return ON_MESH_EDGE;
+ /* Use a pre-computed vert-to-looptri mapping, speeds up things a lot compared to looping over all loopti. */
+ for (int i = 0; i < vert_to_looptri_map[e1_index].count; i++) {
+ const int lt_index = vert_to_looptri_map[e1_index].indices[i];
+ const int v0 = mloop[mlooptri[lt_index].tri[0]].v;
+ const int v1 = mloop[mlooptri[lt_index].tri[1]].v;
+ const int v2 = mloop[mlooptri[lt_index].tri[2]].v;
- /*
- * If target face is connected in UV space as well, just use original index
- */
- s_uv1 = mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv;
- s_uv2 = mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv;
- t_uv1 = mloopuv[mlooptri[target_tri].tri[target_uv1]].uv;
- t_uv2 = mloopuv[mlooptri[target_tri].tri[target_uv2]].uv;
+ BLI_assert(ELEM(e1_index, v0, v1, v2));
- //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 (ELEM(e2_index, v0, v1, v2)) {
+ if (lt_index == cPoint->tri_index)
+ continue;
- if (((s_uv1[0] == t_uv1[0] && s_uv1[1] == t_uv1[1]) &&
- (s_uv2[0] == t_uv2[0] && s_uv2[1] == t_uv2[1]) ) ||
- ((s_uv2[0] == t_uv1[0] && s_uv2[1] == t_uv1[1]) &&
- (s_uv1[0] == t_uv2[0] && s_uv1[1] == t_uv2[1]) ))
- {
- return ((px + neighX[n_index]) + w * (py + neighY[n_index]));
- }
+ target_tri = lt_index;
- /*
- * Find a point that is relatively at same edge position
- * on this other face UV
- */
- lambda = closest_to_line_v2(
- closest_point, pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv);
- if (lambda < 0.0f) lambda = 0.0f;
- if (lambda > 1.0f) lambda = 1.0f;
-
- sub_v2_v2v2(
- dir_vec,
- mloopuv[mlooptri[target_tri].tri[target_uv2]].uv,
- mloopuv[mlooptri[target_tri].tri[target_uv1]].uv);
-
- mul_v2_fl(dir_vec, lambda);
-
- copy_v2_v2(pixel, mloopuv[mlooptri[target_tri].tri[target_uv1]].uv);
- add_v2_v2(pixel, dir_vec);
- pixel[0] = (pixel[0] * (float)w) - 0.5f;
- pixel[1] = (pixel[1] * (float)h) - 0.5f;
-
- final_pixel[0] = (int)floor(pixel[0]);
- final_pixel[1] = (int)floor(pixel[1]);
-
- /* If current pixel uv is outside of texture */
- if (final_pixel[0] < 0 || final_pixel[0] >= w) return OUT_OF_TEXTURE;
- if (final_pixel[1] < 0 || final_pixel[1] >= h) return OUT_OF_TEXTURE;
-
- final_index = final_pixel[0] + w * final_pixel[1];
-
- /* If we ended up to our origin point ( mesh has smaller than pixel sized faces) */
- if (final_index == (px + w * py)) return NOT_FOUND;
- /* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
- if (tempPoints[final_index].tri_index != target_tri) {
- return NOT_FOUND;
+ /* Get edge UV index */
+ target_uv1 = (e1_index == v0) ? 0 : ((e1_index == v1) ? 1 : 2);
+ target_uv2 = (e2_index == v0) ? 0 : ((e2_index == v1) ? 1 : 2);
+ break;
}
+ }
- /*
- * If final point is an "edge pixel", use it's "real" neighbor instead
- */
- if (tempPoints[final_index].neighbour_pixel != -1) final_index = cPoint->neighbour_pixel;
+ /* If none found pixel is on mesh edge */
+ if (target_tri == -1)
+ return ON_MESH_EDGE;
- return final_index;
+ /*
+ * If target face is connected in UV space as well, just use original index
+ */
+ s_uv1 = mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv;
+ s_uv2 = mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv;
+ t_uv1 = mloopuv[mlooptri[target_tri].tri[target_uv1]].uv;
+ t_uv2 = mloopuv[mlooptri[target_tri].tri[target_uv2]].uv;
+
+ //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]) &&
+ (s_uv2[0] == t_uv2[0] && s_uv2[1] == t_uv2[1])) ||
+ ((s_uv2[0] == t_uv1[0] && s_uv2[1] == t_uv1[1]) &&
+ (s_uv1[0] == t_uv2[0] && s_uv1[1] == t_uv2[1])))
+ {
+ return ((px + neighX[n_index]) + w * (py + neighY[n_index]));
}
+
+ /*
+ * Find a point that is relatively at same edge position
+ * on this other face UV
+ */
+ lambda = closest_to_line_v2(
+ closest_point, pixel,
+ mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv,
+ mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv);
+ CLAMP(lambda, 0.0f, 1.0f);
+
+ sub_v2_v2v2(
+ dir_vec,
+ mloopuv[mlooptri[target_tri].tri[target_uv2]].uv,
+ mloopuv[mlooptri[target_tri].tri[target_uv1]].uv);
+
+ mul_v2_fl(dir_vec, lambda);
+
+ copy_v2_v2(pixel, mloopuv[mlooptri[target_tri].tri[target_uv1]].uv);
+ add_v2_v2(pixel, dir_vec);
+ pixel[0] = (pixel[0] * (float)w) - 0.5f;
+ pixel[1] = (pixel[1] * (float)h) - 0.5f;
+
+ final_pixel[0] = (int)floorf(pixel[0]);
+ final_pixel[1] = (int)floorf(pixel[1]);
+
+ /* If current pixel uv is outside of texture */
+ if (final_pixel[0] < 0 || final_pixel[0] >= w || final_pixel[1] < 0 || final_pixel[1] >= h)
+ return OUT_OF_TEXTURE;
+
+ final_index = final_pixel[0] + w * final_pixel[1];
+
+ /* If we ended up to our origin point ( mesh has smaller than pixel sized faces) */
+ if (final_index == (px + w * py))
+ return NOT_FOUND;
+ /* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
+ if (tempPoints[final_index].tri_index != target_tri)
+ return NOT_FOUND;
+
+ /* If final point is an "edge pixel", use it's "real" neighbor instead */
+ if (tempPoints[final_index].neighbour_pixel != -1)
+ final_index = cPoint->neighbour_pixel;
+
+ return final_index;
}
}
-/*
- * Create a surface for uv image sequence format
- */
-int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
+int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, float *progress, short *do_update)
{
/* Antialias jitter point relative coords */
- const float jitter5sample[10] = {
- 0.0f, 0.0f,
- -0.2f, -0.4f,
- 0.2f, 0.4f,
- 0.4f, -0.2f,
- -0.4f, 0.3f,
- };
- int ty;
- int w, h;
- int tottri;
+ const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
char uvname[MAX_CUSTOMDATA_LAYER_NAME];
- int active_points = 0;
- int error = 0;
+ uint32_t active_points = 0;
+ bool error = false;
PaintSurfaceData *sData;
DynamicPaintCanvasSettings *canvas = surface->canvas;
@@ -2132,7 +2468,9 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
Bounds2D *faceBB = NULL;
int *final_index;
- int aa_samples;
+
+ *progress = 0.0f;
+ *do_update = true;
if (!dm)
return setError(canvas, N_("Canvas mesh not updated"));
@@ -2141,7 +2479,7 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
mloop = dm->getLoopArray(dm);
mlooptri = dm->getLoopTriArray(dm);
- tottri = dm->getNumLoopTri(dm);
+ const int tottri = dm->getNumLoopTri(dm);
/* get uv map */
if (CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) {
@@ -2155,7 +2493,8 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
if (surface->image_resolution < 16 || surface->image_resolution > 8192)
return setError(canvas, N_("Invalid resolution"));
- w = h = surface->image_resolution;
+ const int w = surface->image_resolution;
+ const int h = w;
/*
* Start generating the surface
@@ -2163,156 +2502,60 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
printf("DynamicPaint: Preparing UV surface of %ix%i pixels and %i tris.\n", w, h, tottri);
/* Init data struct */
- if (surface->data) dynamicPaint_freeSurfaceData(surface);
+ if (surface->data)
+ dynamicPaint_freeSurfaceData(surface);
sData = surface->data = MEM_callocN(sizeof(PaintSurfaceData), "PaintSurfaceData");
if (!surface->data)
return setError(canvas, N_("Not enough free memory"));
- aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
- tempPoints = (struct PaintUVPoint *) MEM_callocN(w * h * sizeof(struct PaintUVPoint), "Temp PaintUVPoint");
- if (!tempPoints) error = 1;
+ tempPoints = MEM_callocN(w * h * sizeof(*tempPoints), "Temp PaintUVPoint");
+ if (!tempPoints)
+ error = true;
- final_index = (int *) MEM_callocN(w * h * sizeof(int), "Temp UV Final Indexes");
- if (!final_index) error = 1;
+ final_index = MEM_callocN(w * h * sizeof(*final_index), "Temp UV Final Indexes");
+ if (!final_index)
+ error = true;
- tempWeights = (struct Vec3f *) MEM_mallocN(w * h * aa_samples * sizeof(struct Vec3f), "Temp bWeights");
- if (!tempWeights) error = 1;
+ tempWeights = MEM_mallocN(w * h * aa_samples * sizeof(*tempWeights), "Temp bWeights");
+ if (!tempWeights)
+ error = true;
/*
* Generate a temporary bounding box array for UV faces to optimize
* the pixel-inside-a-face search.
*/
if (!error) {
- faceBB = (struct Bounds2D *) MEM_mallocN(tottri * sizeof(struct Bounds2D), "MPCanvasFaceBB");
- if (!faceBB) error = 1;
+ faceBB = MEM_mallocN(tottri * sizeof(*faceBB), "MPCanvasFaceBB");
+ if (!faceBB)
+ error = true;
}
- if (!error)
- for (ty = 0; ty < tottri; ty++) {
- int i;
+ *progress = 0.01f;
+ *do_update = true;
- copy_v2_v2(faceBB[ty].min, mloopuv[mlooptri[ty].tri[0]].uv);
- copy_v2_v2(faceBB[ty].max, mloopuv[mlooptri[ty].tri[0]].uv);
+ if (!error) {
+ for (int i = 0; i < tottri; i++) {
+ copy_v2_v2(faceBB[i].min, mloopuv[mlooptri[i].tri[0]].uv);
+ copy_v2_v2(faceBB[i].max, mloopuv[mlooptri[i].tri[0]].uv);
- for (i = 1; i < 3; i++) {
- CLAMP_MAX(faceBB[ty].min[0], mloopuv[mlooptri[ty].tri[i]].uv[0]);
- CLAMP_MAX(faceBB[ty].min[1], mloopuv[mlooptri[ty].tri[i]].uv[1]);
- CLAMP_MIN(faceBB[ty].max[0], mloopuv[mlooptri[ty].tri[i]].uv[0]);
- CLAMP_MIN(faceBB[ty].max[1], mloopuv[mlooptri[ty].tri[i]].uv[1]);
+ for (int j = 1; j < 3; j++) {
+ minmax_v2v2_v2(faceBB[i].min, faceBB[i].max, mloopuv[mlooptri[i].tri[j]].uv);
}
}
- /*
- * Loop through every pixel and check
- * if pixel is uv-mapped on a canvas face.
- */
- if (!error) {
-#pragma omp parallel for schedule(static)
- for (ty = 0; ty < h; ty++) {
- int tx;
- for (tx = 0; tx < w; tx++) {
- int i, sample;
- int index = tx + w * ty;
- PaintUVPoint *tPoint = (&tempPoints[index]);
-
- bool isInside = false; /* if point is inside a uv face */
-
- float d1[2], d2[2], d3[2], point[5][2];
- float dot00, dot01, dot02, dot11, dot12, invDenom, u, v;
-
- /* Init per pixel settings */
- tPoint->tri_index = -1;
- tPoint->neighbour_pixel = -1;
- tPoint->pixel_index = index;
-
- /* Actual pixel center, used when collision is found */
- point[0][0] = ((float)tx + 0.5f) / w;
- point[0][1] = ((float)ty + 0.5f) / h;
-
- /*
- * A pixel middle sample isn't enough to find very narrow polygons
- * So using 4 samples of each corner too
- */
- point[1][0] = ((float)tx) / w;
- point[1][1] = ((float)ty) / h;
-
- point[2][0] = ((float)tx + 1) / w;
- point[2][1] = ((float)ty) / h;
-
- point[3][0] = ((float)tx) / w;
- point[3][1] = ((float)ty + 1) / h;
-
- point[4][0] = ((float)tx + 1) / w;
- point[4][1] = ((float)ty + 1) / h;
-
-
- /* Loop through samples, starting from middle point */
- for (sample = 0; sample < 5; sample++) {
-
- /* Loop through every face in the mesh */
- for (i = 0; i < tottri; i++) {
-
- /* Check uv bb */
- if (faceBB[i].min[0] > (point[sample][0])) continue;
- if (faceBB[i].min[1] > (point[sample][1])) continue;
- if (faceBB[i].max[0] < (point[sample][0])) continue;
- if (faceBB[i].max[1] < (point[sample][1])) continue;
-
- /* Calculate point inside a triangle check
- * for uv0, 1, 2 */
- sub_v2_v2v2(d1, mloopuv[mlooptri[i].tri[2]].uv, mloopuv[mlooptri[i].tri[0]].uv); /* uv2 - uv0 */
- sub_v2_v2v2(d2, mloopuv[mlooptri[i].tri[1]].uv, mloopuv[mlooptri[i].tri[0]].uv); /* uv1 - uv0 */
- sub_v2_v2v2(d3, point[sample], mloopuv[mlooptri[i].tri[0]].uv); /* point - uv0 */
-
- dot00 = d1[0] * d1[0] + d1[1] * d1[1];
- dot01 = d1[0] * d2[0] + d1[1] * d2[1];
- dot02 = d1[0] * d3[0] + d1[1] * d3[1];
- dot11 = d2[0] * d2[0] + d2[1] * d2[1];
- dot12 = d2[0] * d3[0] + d2[1] * d3[1];
-
- invDenom = (dot00 * dot11 - dot01 * dot01);
- invDenom = invDenom ? 1.0f / invDenom : 1.0f;
- u = (dot11 * dot02 - dot01 * dot12) * invDenom;
- v = (dot00 * dot12 - dot01 * dot02) * invDenom;
-
- if ((u > 0) && (v > 0) && (u + v < 1)) { isInside = true; } /* is inside a triangle */
-
- /*
- * If point was inside the face
- */
- if (isInside) {
-
- float uv1co[2], uv2co[2], uv3co[2], uv[2];
- int j;
-
- /* Get triagnle uvs */
- copy_v2_v2(uv1co, mloopuv[mlooptri[i].tri[0]].uv);
- copy_v2_v2(uv2co, mloopuv[mlooptri[i].tri[1]].uv);
- copy_v2_v2(uv3co, mloopuv[mlooptri[i].tri[2]].uv);
-
- /* Add b-weights per anti-aliasing sample */
- 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;
-
- barycentric_weights_v2(uv1co, uv2co, uv3co, uv, tempWeights[index * aa_samples + j].v);
- }
-
- /* Set surface point face values */
- tPoint->tri_index = i;
+ *progress = 0.02f;
+ *do_update = true;
- /* save vertex indexes */
- tPoint->v1 = mloop[mlooptri[i].tri[0]].v;
- tPoint->v2 = mloop[mlooptri[i].tri[1]].v;
- tPoint->v3 = mloop[mlooptri[i].tri[2]].v;
+ /* Loop through every pixel and check if pixel is uv-mapped on a canvas face. */
+ DynamicPaintCreateUVSurfaceData data = {
+ .surface = surface, .tempPoints = tempPoints, .tempWeights = tempWeights,
+ .mlooptri = mlooptri, .mloopuv = mloopuv, .mloop = mloop, .tottri = tottri,
+ .faceBB = faceBB,
+ };
+ BLI_task_parallel_range(0, h, &data, dynamic_paint_create_uv_surface_direct_cb, h > 64 || tottri > 1000);
- sample = 5; /* make sure we exit sample loop as well */
- break;
- }
- }
- } /* sample loop */
- }
- }
+ *progress = 0.04f;
+ *do_update = true;
/*
* Now loop through every pixel that was left without index
@@ -2320,87 +2563,11 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
* If so use that polygon as pixel surface.
* (To avoid seams on uv island edges)
*/
-#pragma omp parallel for schedule(static)
- for (ty = 0; ty < h; ty++) {
- int tx;
- for (tx = 0; tx < w; tx++) {
- int index = tx + w * ty;
- PaintUVPoint *tPoint = (&tempPoints[index]);
-
- /* If point isn't't on canvas mesh */
- if (tPoint->tri_index == -1) {
- int u_min, u_max, v_min, v_max;
- int u, v, ind;
- float point[2];
-
- /* get loop area */
- u_min = (tx > 0) ? -1 : 0;
- u_max = (tx < (w - 1)) ? 1 : 0;
- v_min = (ty > 0) ? -1 : 0;
- v_max = (ty < (h - 1)) ? 1 : 0;
-
- point[0] = ((float)tx + 0.5f) / w;
- point[1] = ((float)ty + 0.5f) / h;
-
- /* search through defined area for neighbor */
- for (u = u_min; u <= u_max; u++)
- for (v = v_min; v <= v_max; v++) {
- /* if not this pixel itself */
- if (u != 0 || v != 0) {
- ind = (tx + u) + w * (ty + v);
-
- /* if neighbor has index */
- if (tempPoints[ind].tri_index != -1) {
-
- float uv1co[2], uv2co[2], uv3co[2], uv[2];
- int i = tempPoints[ind].tri_index, j;
-
- /* Now calculate pixel data for this pixel as it was on polygon surface */
- copy_v2_v2(uv1co, mloopuv[mlooptri[i].tri[0]].uv);
- copy_v2_v2(uv2co, mloopuv[mlooptri[i].tri[1]].uv);
- copy_v2_v2(uv3co, mloopuv[mlooptri[i].tri[2]].uv);
-
- /* Add b-weights per anti-aliasing sample */
- for (j = 0; j < aa_samples; j++) {
-
- uv[0] = point[0] + jitter5sample[j * 2] / w;
- uv[1] = point[1] + jitter5sample[j * 2 + 1] / h;
- barycentric_weights_v2(uv1co, uv2co, uv3co, uv, tempWeights[index * aa_samples + j].v);
- }
-
- /* Set values */
- tPoint->neighbour_pixel = ind; /* tri index */
-
- /* save vertex indexes */
- tPoint->v1 = mloop[mlooptri[i].tri[0]].v;
- tPoint->v2 = mloop[mlooptri[i].tri[1]].v;
- tPoint->v3 = mloop[mlooptri[i].tri[2]].v;
-
- u = u_max + 1; /* make sure we exit outer loop as well */
- break;
- }
- }
- }
- }
- }
- }
+ data.active_points = &active_points;
+ BLI_task_parallel_range(0, h, &data, dynamic_paint_create_uv_surface_neighbor_cb, h > 64);
- /*
- * When base loop is over convert found neighbor indexes to real ones
- * Also count the final number of active surface points
- */
- for (ty = 0; ty < h; ty++) {
- int tx;
- for (tx = 0; tx < w; tx++) {
- int index = tx + w * ty;
- PaintUVPoint *tPoint = &tempPoints[index];
-
- if (tPoint->tri_index == -1 && tPoint->neighbour_pixel != -1)
- tPoint->tri_index = tempPoints[tPoint->neighbour_pixel].tri_index;
- if (tPoint->tri_index != -1)
- active_points++;
- }
- }
+ *progress = 0.06f;
+ *do_update = true;
/* Generate surface adjacency data. */
{
@@ -2416,25 +2583,31 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
}
/* allocate memory */
sData->total_points = w * h;
- dynamicPaint_initAdjacencyData(surface, 1);
+ dynamicPaint_initAdjacencyData(surface, true);
if (sData->adj_data) {
PaintAdjData *ed = sData->adj_data;
- unsigned int n_pos = 0;
- for (ty = 0; ty < h; ty++) {
- int tx;
- for (tx = 0; tx < w; tx++) {
- int index = tx + w * ty;
+ int n_pos = 0;
+
+ MeshElemMap *vert_to_looptri_map;
+ int *vert_to_looptri_map_mem;
+
+ BKE_mesh_vert_looptri_map_create(
+ &vert_to_looptri_map, &vert_to_looptri_map_mem,
+ dm->getVertArray(dm), dm->getNumVerts(dm), mlooptri, tottri, mloop, dm->getNumLoops(dm));
+
+ for (int ty = 0; ty < h; ty++) {
+ for (int tx = 0; tx < w; tx++) {
+ const int index = tx + w * ty;
if (tempPoints[index].tri_index != -1) {
ed->n_index[final_index[index]] = n_pos;
ed->n_num[final_index[index]] = 0;
for (int i = 0; i < 8; i++) {
-
- /* Try to find a neighboring pixel in defined direction
- * If not found, -1 is returned */
- int n_target = dynamicPaint_findNeighbourPixel(tempPoints, dm, uvname, w, h, tx, ty, i);
+ /* Try to find a neighboring pixel in defined direction. If not found, -1 is returned */
+ const int n_target = dynamic_paint_find_neighbour_pixel(
+ &data, vert_to_looptri_map, w, h, tx, ty, i);
if (n_target >= 0) {
ed->n_target[n_pos] = final_index[n_target];
@@ -2448,43 +2621,50 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
}
}
}
+
+ MEM_freeN(vert_to_looptri_map);
+ MEM_freeN(vert_to_looptri_map_mem);
}
}
+ *progress = 0.08f;
+ *do_update = true;
+
/* Create final surface data without inactive points */
- {
- ImgSeqFormatData *f_data = MEM_callocN(sizeof(struct ImgSeqFormatData), "ImgSeqFormatData");
- if (f_data) {
- f_data->uv_p = MEM_callocN(active_points * sizeof(struct PaintUVPoint), "PaintUVPoint");
- f_data->barycentricWeights = MEM_callocN(active_points * aa_samples * sizeof(struct Vec3f), "PaintUVPoint");
+ ImgSeqFormatData *f_data = MEM_callocN(sizeof(*f_data), "ImgSeqFormatData");
+ if (f_data) {
+ f_data->uv_p = MEM_callocN(active_points * sizeof(*f_data->uv_p), "PaintUVPoint");
+ f_data->barycentricWeights = MEM_callocN(active_points * aa_samples * sizeof(*f_data->barycentricWeights),
+ "PaintUVPoint");
- if (!f_data->uv_p || !f_data->barycentricWeights) error = 1;
- }
- else {
+ if (!f_data->uv_p || !f_data->barycentricWeights)
error = 1;
- }
+ }
+ else {
+ error = 1;
+ }
- 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);
- }
+ /* in case of allocation error, free everything */
+ if (error) {
+ if (f_data) {
+ if (f_data->uv_p)
+ MEM_freeN(f_data->uv_p);
+ if (f_data->barycentricWeights)
+ MEM_freeN(f_data->barycentricWeights);
+ MEM_freeN(f_data);
}
- else {
- int index, cursor = 0;
- sData->total_points = active_points;
- sData->format_data = f_data;
-
- for (index = 0; index < (w * h); index++) {
- if (tempPoints[index].tri_index != -1) {
- memcpy(&f_data->uv_p[cursor], &tempPoints[index], sizeof(PaintUVPoint));
- memcpy(&f_data->barycentricWeights[cursor * aa_samples], &tempWeights[index * aa_samples], sizeof(Vec3f) * aa_samples);
- cursor++;
- }
+ sData->total_points = 0;
+ }
+ else {
+ sData->total_points = (int)active_points;
+ sData->format_data = f_data;
+
+ for (int index = 0, cursor = 0; index < (w * h); index++) {
+ if (tempPoints[index].tri_index != -1) {
+ memcpy(&f_data->uv_p[cursor], &tempPoints[index], sizeof(PaintUVPoint));
+ memcpy(&f_data->barycentricWeights[cursor * aa_samples], &tempWeights[index * aa_samples],
+ sizeof(*tempWeights) * aa_samples);
+ cursor++;
}
}
}
@@ -2492,10 +2672,14 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
if (error == 1)
setError(canvas, N_("Not enough free memory"));
- if (faceBB) MEM_freeN(faceBB);
- if (tempPoints) MEM_freeN(tempPoints);
- if (tempWeights) MEM_freeN(tempWeights);
- if (final_index) MEM_freeN(final_index);
+ if (faceBB)
+ MEM_freeN(faceBB);
+ if (tempPoints)
+ MEM_freeN(tempPoints);
+ if (tempWeights)
+ MEM_freeN(tempWeights);
+ if (final_index)
+ MEM_freeN(final_index);
/* Init surface type data */
if (!error) {
@@ -2505,38 +2689,126 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
/* -----------------------------------------------------------------
* For debug, output pixel statuses to the color map
* -----------------------------------------------------------------*/
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++)
- {
+ for (index = 0; index < sData->total_points; index++) {
ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
PaintUVPoint *uvPoint = &((PaintUVPoint *)f_data->uv_p)[index];
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
pPoint->alpha = 1.0f;
/* Every pixel that is assigned as "edge pixel" gets blue color */
- if (uvPoint->neighbour_pixel != -1) pPoint->color[2] = 1.0f;
+ if (uvPoint->neighbour_pixel != -1)
+ pPoint->color[2] = 1.0f;
/* and every pixel that finally got an polygon gets red color */
- if (uvPoint->tri_index != -1) pPoint->color[0] = 1.0f;
/* green color shows pixel face index hash */
- if (uvPoint->tri_index != -1) pPoint->color[1] = (float)(uvPoint->tri_index % 255) / 256.0f;
+ if (uvPoint->tri_index != -1) {
+ pPoint->color[0] = 1.0f;
+ pPoint->color[1] = (float)(uvPoint->tri_index % 255) / 256.0f;
+ }
}
-
#endif
+
dynamicPaint_setInitialColor(scene, surface);
}
+ *progress = 0.09f;
+ *do_update = true;
+
return (error == 0);
}
/*
* Outputs an image file from uv surface data.
*/
+typedef struct DynamicPaintOutputSurfaceImageData {
+ const DynamicPaintSurface *surface;
+ ImBuf *ibuf;
+} DynamicPaintOutputSurfaceImageData;
+
+static void dynamic_paint_output_surface_image_paint_cb(void *userdata, const int index)
+{
+ const DynamicPaintOutputSurfaceImageData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintPoint *point = &((PaintPoint *)surface->data->type_data)[index];
+
+ ImBuf *ibuf = data->ibuf;
+ /* image buffer position */
+ const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
+
+ /* blend wet and dry layers */
+ blendColors(point->color, point->color[3], point->e_color, point->e_color[3], &ibuf->rect_float[pos]);
+
+ /* Multiply color by alpha if enabled */
+ if (surface->flags & MOD_DPAINT_MULALPHA) {
+ mul_v3_fl(&ibuf->rect_float[pos], ibuf->rect_float[pos + 3]);
+ }
+}
+
+static void dynamic_paint_output_surface_image_displace_cb(void *userdata, const int index)
+{
+ const DynamicPaintOutputSurfaceImageData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ float depth = ((float *)surface->data->type_data)[index];
+
+ ImBuf *ibuf = data->ibuf;
+ /* image buffer position */
+ const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
+
+ if (surface->depth_clamp)
+ depth /= surface->depth_clamp;
+
+ if (surface->disp_type == MOD_DPAINT_DISP_DISPLACE) {
+ depth = (0.5f - depth / 2.0f);
+ }
+
+ CLAMP(depth, 0.0f, 1.0f);
+
+ copy_v3_fl(&ibuf->rect_float[pos], depth);
+ ibuf->rect_float[pos + 3] = 1.0f;
+}
+
+static void dynamic_paint_output_surface_image_wave_cb(void *userdata, const int index)
+{
+ const DynamicPaintOutputSurfaceImageData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintWavePoint *wPoint = &((PaintWavePoint *)surface->data->type_data)[index];
+ float depth = wPoint->height;
+
+ ImBuf *ibuf = data->ibuf;
+ /* image buffer position */
+ const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
+
+ if (surface->depth_clamp)
+ depth /= surface->depth_clamp;
+
+ depth = (0.5f + depth / 2.0f);
+ CLAMP(depth, 0.0f, 1.0f);
+
+ copy_v3_fl(&ibuf->rect_float[pos], depth);
+ ibuf->rect_float[pos + 3] = 1.0f;
+}
+
+static void dynamic_paint_output_surface_image_wetmap_cb(void *userdata, const int index)
+{
+ const DynamicPaintOutputSurfaceImageData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintPoint *point = &((PaintPoint *)surface->data->type_data)[index];
+
+ ImBuf *ibuf = data->ibuf;
+ /* image buffer position */
+ const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
+
+ copy_v3_fl(&ibuf->rect_float[pos], (point->wetness > 1.0f) ? 1.0f : point->wetness);
+ ibuf->rect_float[pos + 3] = 1.0f;
+}
+
void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filename, short output_layer)
{
- int index;
ImBuf *ibuf = NULL;
PaintSurfaceData *sData = surface->data;
- ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
/* OpenEXR or PNG */
int format = (surface->image_fileformat & MOD_DPAINT_IMGFORMAT_OPENEXR) ? R_IMF_IMTYPE_OPENEXR : R_IMF_IMTYPE_PNG;
char output_file[FILE_MAX];
@@ -2547,7 +2819,8 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam
}
/* if selected format is openexr, but current build doesnt support one */
#ifndef WITH_OPENEXR
- if (format == R_IMF_IMTYPE_OPENEXR) format = R_IMF_IMTYPE_PNG;
+ if (format == R_IMF_IMTYPE_OPENEXR)
+ format = R_IMF_IMTYPE_PNG;
#endif
BLI_strncpy(output_file, filename, sizeof(output_file));
BKE_image_path_ensure_ext_from_imtype(output_file, format);
@@ -2563,82 +2836,66 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam
return;
}
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- int pos = f_data->uv_p[index].pixel_index * 4; /* image buffer position */
-
- /* Set values of preferred type */
- if (output_layer == 1) {
- /* wetmap */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- PaintPoint *point = &((PaintPoint *)sData->type_data)[index];
- float value = (point->wetness > 1.0f) ? 1.0f : point->wetness;
-
- ibuf->rect_float[pos] = value;
- ibuf->rect_float[pos + 1] = value;
- ibuf->rect_float[pos + 2] = value;
- ibuf->rect_float[pos + 3] = 1.0f;
- }
- }
- else if (output_layer == 0) {
- /* Paintmap */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- PaintPoint *point = &((PaintPoint *)sData->type_data)[index];
-
- /* blend wet and dry layers */
- blendColors(point->color, point->color[3], point->e_color, point->e_color[3], &ibuf->rect_float[pos]);
-
- /* Multiply color by alpha if enabled */
- if (surface->flags & MOD_DPAINT_MULALPHA) {
- 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];
- }
+ DynamicPaintOutputSurfaceImageData data = {.surface = surface, .ibuf = ibuf};
+ switch(surface->type) {
+ case MOD_DPAINT_SURFACE_T_PAINT:
+ switch (output_layer) {
+ case 0:
+ BLI_task_parallel_range(0, sData->total_points, &data,
+ dynamic_paint_output_surface_image_paint_cb, sData->total_points > 10000);
+ break;
+ case 1:
+ BLI_task_parallel_range(0, sData->total_points, &data,
+ dynamic_paint_output_surface_image_wetmap_cb, sData->total_points > 10000);
+ break;
+ default:
+ BLI_assert(0);
+ break;
}
- /* displace */
- else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
- float depth = ((float *)sData->type_data)[index];
- if (surface->depth_clamp)
- depth /= surface->depth_clamp;
-
- if (surface->disp_type == MOD_DPAINT_DISP_DISPLACE) {
- depth = (0.5f - depth / 2.0f);
- }
-
- CLAMP(depth, 0.0f, 1.0f);
-
- ibuf->rect_float[pos] = depth;
- ibuf->rect_float[pos + 1] = depth;
- ibuf->rect_float[pos + 2] = depth;
- ibuf->rect_float[pos + 3] = 1.0f;
+ break;
+ case MOD_DPAINT_SURFACE_T_DISPLACE:
+ switch (output_layer) {
+ case 0:
+ BLI_task_parallel_range(0, sData->total_points, &data,
+ dynamic_paint_output_surface_image_displace_cb, sData->total_points > 10000);
+ break;
+ case 1:
+ break;
+ default:
+ BLI_assert(0);
+ break;
}
- /* waves */
- else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
- PaintWavePoint *wPoint = &((PaintWavePoint *)sData->type_data)[index];
- float depth = wPoint->height;
- if (surface->depth_clamp)
- depth /= surface->depth_clamp;
- depth = (0.5f + depth / 2.0f);
- CLAMP(depth, 0.0f, 1.0f);
-
- ibuf->rect_float[pos] = depth;
- ibuf->rect_float[pos + 1] = depth;
- ibuf->rect_float[pos + 2] = depth;
- ibuf->rect_float[pos + 3] = 1.0f;
+ break;
+ case MOD_DPAINT_SURFACE_T_WAVE:
+ switch (output_layer) {
+ case 0:
+ BLI_task_parallel_range(0, sData->total_points, &data,
+ dynamic_paint_output_surface_image_wave_cb, sData->total_points > 10000);
+ break;
+ case 1:
+ break;
+ default:
+ BLI_assert(0);
+ break;
}
- }
+ break;
+ default:
+ BLI_assert(0);
+ break;
}
/* Set output format, png in case exr isn't supported */
- ibuf->ftype = IMB_FTYPE_PNG;
- ibuf->foptions.quality = 15;
-
#ifdef WITH_OPENEXR
if (format == R_IMF_IMTYPE_OPENEXR) { /* OpenEXR 32-bit float */
ibuf->ftype = IMB_FTYPE_OPENEXR;
ibuf->foptions.flag |= OPENEXR_COMPRESS;
}
+ else
#endif
+ {
+ ibuf->ftype = IMB_FTYPE_PNG;
+ ibuf->foptions.quality = 15;
+ }
/* Save image */
IMB_saveiff(ibuf, output_file, IB_rectfloat);
@@ -2704,7 +2961,7 @@ static void dynamicPaint_freeBrushMaterials(BrushMaterials *bMats)
* Get material diffuse color and alpha (including linked textures) in given coordinates
*/
static void dynamicPaint_doMaterialTex(
- BrushMaterials *bMats, float color[3], float *alpha, Object *brushOb,
+ const BrushMaterials *bMats, float color[3], float *alpha, Object *brushOb,
const float volume_co[3], const float surface_co[3],
int triIndex, DerivedMesh *orcoDm)
{
@@ -2717,9 +2974,11 @@ static void dynamicPaint_doMaterialTex(
if (mat == NULL) {
if (bMats->ob_mats) {
int mat_nr = mpoly[mlooptri[triIndex].poly].mat_nr;
- if (mat_nr >= (*give_totcolp(brushOb))) return;
+ if (mat_nr >= (*give_totcolp(brushOb)))
+ return;
mat = bMats->ob_mats[mat_nr];
- if (mat == NULL) return; /* No material assigned */
+ if (mat == NULL)
+ return; /* No material assigned */
}
else {
return;
@@ -2732,7 +2991,7 @@ static void dynamicPaint_doMaterialTex(
/***************************** Ray / Nearest Point Utils ******************************/
-/* A modified callback to bvh tree raycast. The tree must bust have been built using bvhtree_from_mesh_looptri.
+/* A modified callback to bvh tree raycast. The tree must have been built using bvhtree_from_mesh_looptri.
* 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.
@@ -2758,10 +3017,9 @@ static void mesh_tris_spherecast_dp(void *userdata, int index, const BVHTreeRay
hit->dist = dist;
hit->no[0] = 0.0f;
}
-
}
-/* A modified callback to bvh tree nearest point. The tree must bust have been built using bvhtree_from_mesh_looptri.
+/* A modified callback to bvh tree nearest point. The tree must have been built using bvhtree_from_mesh_looptri.
* userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree.
*
* To optimize brush detection speed this doesn't calculate hit normal.
@@ -2804,15 +3062,15 @@ static void mesh_tris_nearest_point_dp(void *userdata, int index, const float co
* operations when using substeps
*/
static void dynamicPaint_mixPaintColors(
- DynamicPaintSurface *surface, int index, int paintFlags,
- const float paintColor[3], float *paintAlpha, float *paintWetness, float *timescale)
+ const DynamicPaintSurface *surface, const int index, const int paintFlags,
+ const float paintColor[3], const float paintAlpha, const float paintWetness, const float timescale)
{
PaintPoint *pPoint = &((PaintPoint *)surface->data->type_data)[index];
/* Add paint */
if (!(paintFlags & MOD_DPAINT_ERASE)) {
float mix[4];
- float temp_alpha = (*paintAlpha) * ((paintFlags & MOD_DPAINT_ABS_ALPHA) ? 1.0f : (*timescale));
+ float temp_alpha = paintAlpha * ((paintFlags & MOD_DPAINT_ABS_ALPHA) ? 1.0f : timescale);
/* mix brush color with wet layer color */
blendColors(pPoint->e_color, pPoint->e_color[3], paintColor, temp_alpha, mix);
@@ -2821,11 +3079,11 @@ static void dynamicPaint_mixPaintColors(
/* mix wetness and alpha depending on selected alpha mode */
if (paintFlags & MOD_DPAINT_ABS_ALPHA) {
/* update values to the brush level unless theyre higher already */
- CLAMP_MIN(pPoint->e_color[3], *paintAlpha);
- CLAMP_MIN(pPoint->wetness, *paintWetness);
+ CLAMP_MIN(pPoint->e_color[3], paintAlpha);
+ CLAMP_MIN(pPoint->wetness, paintWetness);
}
else {
- float wetness = (*paintWetness);
+ float wetness = paintWetness;
CLAMP(wetness, 0.0f, 1.0f);
pPoint->e_color[3] = mix[3];
pPoint->wetness = pPoint->wetness * (1.0f - wetness) + wetness;
@@ -2839,7 +3097,7 @@ static void dynamicPaint_mixPaintColors(
else {
float a_ratio, a_highest;
float wetness;
- float invFact = 1.0f - (*paintAlpha);
+ float invFact = 1.0f - paintAlpha;
/*
* Make highest alpha to match erased value
@@ -2855,47 +3113,57 @@ static void dynamicPaint_mixPaintColors(
}
}
else {
- pPoint->e_color[3] -= (*paintAlpha) * (*timescale);
+ pPoint->e_color[3] -= paintAlpha * timescale;
CLAMP_MIN(pPoint->e_color[3], 0.0f);
- pPoint->color[3] -= (*paintAlpha) * (*timescale);
+ pPoint->color[3] -= paintAlpha * timescale;
CLAMP_MIN(pPoint->color[3], 0.0f);
}
- wetness = (1.0f - (*paintWetness)) * pPoint->e_color[3];
+ wetness = (1.0f - paintWetness) * pPoint->e_color[3];
CLAMP_MAX(pPoint->wetness, wetness);
}
}
/* applies given brush intersection value for wave surface */
-static void dynamicPaint_mixWaveHeight(PaintWavePoint *wPoint, DynamicPaintBrushSettings *brush, float isect_height)
+static void dynamicPaint_mixWaveHeight(
+ PaintWavePoint *wPoint, const DynamicPaintBrushSettings *brush, float isect_height)
{
- float isect_change = isect_height - wPoint->brush_isect;
- int hit = 0;
+ const float isect_change = isect_height - wPoint->brush_isect;
+ const float wave_factor = brush->wave_factor;
+ bool hit = false;
+
/* intersection marked regardless of brush type or hit */
wPoint->brush_isect = isect_height;
wPoint->state = DPAINT_WAVE_ISECT_CHANGED;
- isect_height *= brush->wave_factor;
+ isect_height *= 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 (wave_factor > 0.0f && wPoint->height > isect_height)
+ hit = true;
+ else if (wave_factor < 0.0f && wPoint->height < isect_height)
+ hit = true;
if (hit) {
- if (brush->wave_type == MOD_DPAINT_WAVEB_DEPTH) {
- wPoint->height = isect_height;
- wPoint->state = DPAINT_WAVE_OBSTACLE;
- 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)
- wPoint->state = DPAINT_WAVE_REFLECT_ONLY;
- else if (brush->wave_type == MOD_DPAINT_WAVEB_CHANGE) {
- if (isect_change < 0.0f)
- wPoint->height += isect_change * brush->wave_factor;
+ switch (brush->wave_type) {
+ case MOD_DPAINT_WAVEB_DEPTH:
+ wPoint->height = isect_height;
+ wPoint->state = DPAINT_WAVE_OBSTACLE;
+ wPoint->velocity = 0.0f;
+ break;
+ case MOD_DPAINT_WAVEB_FORCE:
+ wPoint->velocity = isect_height;
+ break;
+ case MOD_DPAINT_WAVEB_REFLECT:
+ wPoint->state = DPAINT_WAVE_REFLECT_ONLY;
+ break;
+ case MOD_DPAINT_WAVEB_CHANGE:
+ if (isect_change < 0.0f)
+ wPoint->height += isect_change * wave_factor;
+ break;
+ default:
+ BLI_assert(0);
+ break;
}
}
}
@@ -2903,8 +3171,9 @@ static void dynamicPaint_mixWaveHeight(PaintWavePoint *wPoint, DynamicPaintBrush
/*
* add brush results to the surface data depending on surface type
*/
-static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned int index, DynamicPaintBrushSettings *brush,
- float paint[3], float influence, float depth, float vel_factor, float timescale)
+static void dynamicPaint_updatePointData(
+ const DynamicPaintSurface *surface, const int index, const DynamicPaintBrushSettings *brush,
+ float paint[3], float influence, float depth, float vel_factor, const float timescale)
{
PaintSurfaceData *sData = surface->data;
float strength;
@@ -2924,9 +3193,7 @@ static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned
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];
+ copy_v3_v3(paint, coba_res);
}
if (brush->flags & MOD_DPAINT_VELOCITY_ALPHA)
strength *= coba_res[3];
@@ -2937,12 +3204,10 @@ static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned
/* mix paint surface */
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
-
float paintWetness = brush->wetness * strength;
float paintAlpha = strength;
- dynamicPaint_mixPaintColors(surface, index, brush->flags, paint, &paintAlpha, &paintWetness, &timescale);
-
+ dynamicPaint_mixPaintColors(surface, index, brush->flags, paint, paintAlpha, paintWetness, timescale);
}
/* displace surface */
else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
@@ -2957,10 +3222,10 @@ static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned
if (brush->flags & MOD_DPAINT_ERASE) {
value[index] *= (1.0f - strength);
- if (value[index] < 0.0f) value[index] = 0.0f;
+ CLAMP_MIN(value[index], 0.0f);
}
else {
- if (value[index] < depth) value[index] = depth;
+ CLAMP_MIN(value[index], depth);
}
}
/* vertex weight group surface */
@@ -2969,10 +3234,10 @@ static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned
if (brush->flags & MOD_DPAINT_ERASE) {
value[index] *= (1.0f - strength);
- if (value[index] < 0.0f) value[index] = 0.0f;
+ CLAMP_MIN(value[index], 0.0f);
}
else {
- if (value[index] < strength) value[index] = strength;
+ CLAMP_MIN(value[index], strength);
}
}
/* wave surface */
@@ -2981,8 +3246,7 @@ static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned
CLAMP(depth, 0.0f - brush->wave_clamp, brush->wave_clamp);
}
- dynamicPaint_mixWaveHeight(&((PaintWavePoint *)sData->type_data)[index],
- brush, 0.0f - depth);
+ dynamicPaint_mixWaveHeight(&((PaintWavePoint *)sData->type_data)[index], brush, 0.0f - depth);
}
/* doing velocity based painting */
@@ -2992,19 +3256,57 @@ static void dynamicPaint_updatePointData(DynamicPaintSurface *surface, unsigned
}
/* checks whether surface and brush bounds intersect depending on brush type */
-static int meshBrush_boundsIntersect(Bounds3D *b1, Bounds3D *b2, DynamicPaintBrushSettings *brush, float brush_radius)
+static bool meshBrush_boundsIntersect(Bounds3D *b1, Bounds3D *b2, DynamicPaintBrushSettings *brush, float brush_radius)
{
if (brush->collision == MOD_DPAINT_COL_VOLUME)
return boundsIntersect(b1, b2);
else if (brush->collision == MOD_DPAINT_COL_DIST || brush->collision == MOD_DPAINT_COL_VOLDIST)
return boundsIntersectDist(b1, b2, brush_radius);
- else return 1;
+ return true;
}
/* calculate velocity for mesh vertices */
-static void dynamicPaint_brushMeshCalculateVelocity(Scene *scene, Object *ob, DynamicPaintBrushSettings *brush, Vec3f **brushVel, float timescale)
+typedef struct DynamicPaintBrushVelocityData {
+ Vec3f *brush_vel;
+
+ const MVert *mvert_p;
+ const MVert *mvert_c;
+
+ float (*obmat)[4];
+ float (*prev_obmat)[4];
+
+ const float timescale;
+} DynamicPaintBrushVelocityData;
+
+static void dynamic_paint_brush_velocity_compute_cb(void *userdata, const int i)
+{
+ const DynamicPaintBrushVelocityData *data = userdata;
+
+ Vec3f *brush_vel = data->brush_vel;
+
+ const MVert *mvert_p = data->mvert_p;
+ const MVert *mvert_c = data->mvert_c;
+
+ float (*obmat)[4] = data->obmat;
+ float (*prev_obmat)[4] = data->prev_obmat;
+
+ const float timescale = data->timescale;
+
+ float p1[3], p2[3];
+
+ copy_v3_v3(p1, mvert_p[i].co);
+ mul_m4_v3(prev_obmat, p1);
+
+ copy_v3_v3(p2, mvert_c[i].co);
+ mul_m4_v3(obmat, p2);
+
+ sub_v3_v3v3(brush_vel[i].v, p2, p1);
+ mul_v3_fl(brush_vel[i].v, 1.0f / timescale);
+}
+
+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;
@@ -3024,7 +3326,8 @@ static void dynamicPaint_brushMeshCalculateVelocity(Scene *scene, Object *ob, Dy
scene->r.cfra = prev_fra;
scene->r.subframe = prev_sfra;
- BKE_object_modifier_update_subframe(scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ BKE_object_modifier_update_subframe(
+ scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
dm_p = CDDM_copy(brush->dm);
numOfVerts_p = dm_p->getNumVerts(dm_p);
mvert_p = dm_p->getVertArray(dm_p);
@@ -3034,33 +3337,27 @@ static void dynamicPaint_brushMeshCalculateVelocity(Scene *scene, Object *ob, Dy
scene->r.cfra = cur_fra;
scene->r.subframe = cur_sfra;
- BKE_object_modifier_update_subframe(scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ BKE_object_modifier_update_subframe(
+ scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
dm_c = brush->dm;
numOfVerts_c = dm_c->getNumVerts(dm_c);
mvert_c = dm_p->getVertArray(dm_c);
(*brushVel) = (struct Vec3f *) MEM_mallocN(numOfVerts_c * sizeof(Vec3f), "Dynamic Paint brush velocity");
- if (!(*brushVel)) return;
+ if (!(*brushVel))
+ return;
- /* if mesh is constructive -> num of verts has changed,
- * only use current frame derived mesh */
+ /* if mesh is constructive -> num of verts has changed, only use current frame derived mesh */
if (numOfVerts_p != numOfVerts_c)
mvert_p = mvert_c;
/* calculate speed */
-#pragma omp parallel for schedule(static)
- for (i = 0; i < numOfVerts_c; i++) {
- float p1[3], p2[3];
-
- copy_v3_v3(p1, mvert_p[i].co);
- mul_m4_v3(prev_obmat, p1);
-
- copy_v3_v3(p2, mvert_c[i].co);
- mul_m4_v3(ob->obmat, p2);
-
- sub_v3_v3v3((*brushVel)[i].v, p2, p1);
- mul_v3_fl((*brushVel)[i].v, 1.0f / timescale);
- }
+ DynamicPaintBrushVelocityData data = {
+ .brush_vel = *brushVel,
+ .mvert_p = mvert_p, .mvert_c = mvert_c, .obmat = ob->obmat, .prev_obmat = prev_obmat,
+ .timescale = timescale,
+ };
+ BLI_task_parallel_range(0, numOfVerts_c, &data, dynamic_paint_brush_velocity_compute_cb, numOfVerts_c > 10000);
dm_p->release(dm_p);
}
@@ -3084,13 +3381,15 @@ static void dynamicPaint_brushObjectCalculateVelocity(Scene *scene, Object *ob,
/* previous frame dm */
scene->r.cfra = prev_fra;
scene->r.subframe = prev_sfra;
- BKE_object_modifier_update_subframe(scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ BKE_object_modifier_update_subframe(
+ scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
copy_m4_m4(prev_obmat, ob->obmat);
/* current frame dm */
scene->r.cfra = cur_fra;
scene->r.subframe = cur_sfra;
- BKE_object_modifier_update_subframe(scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ BKE_object_modifier_update_subframe(
+ scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
/* calculate speed */
mul_m4_v3(prev_obmat, prev_loc);
@@ -3100,9 +3399,365 @@ static void dynamicPaint_brushObjectCalculateVelocity(Scene *scene, Object *ob,
mul_v3_fl(brushVel->v, 1.0f / timescale);
}
+typedef struct DynamicPaintPaintData {
+ const DynamicPaintSurface *surface;
+ const DynamicPaintBrushSettings *brush;
+ Object *brushOb;
+ const BrushMaterials *bMats;
+ const Scene *scene;
+ const float timescale;
+ const int c_index;
+
+ DerivedMesh *dm;
+ const MVert *mvert;
+ const MLoop *mloop;
+ const MLoopTri *mlooptri;
+ const float brush_radius;
+ const float *avg_brushNor;
+ const Vec3f *brushVelocity;
+
+ const float solidradius;
+
+ void *treeData;
+
+ float *pointCoord;
+} DynamicPaintPaintData;
+
/*
* Paint a brush object mesh to the surface
*/
+static void dynamic_paint_paint_mesh_cell_point_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int id, const int UNUSED(threadid))
+{
+ const DynamicPaintPaintData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const PaintBakeData *bData = sData->bData;
+ VolumeGrid *grid = bData->grid;
+
+ const DynamicPaintBrushSettings *brush = data->brush;
+ Object *brushOb = data->brushOb;
+ const BrushMaterials *bMats = data->bMats;
+
+ const Scene *scene = data->scene;
+ const float timescale = data->timescale;
+ const int c_index = data->c_index;
+
+ DerivedMesh *dm = data->dm;
+ const MVert *mvert = data->mvert;
+ const MLoop *mloop = data->mloop;
+ const MLoopTri *mlooptri = data->mlooptri;
+ const float brush_radius = data->brush_radius;
+ const float *avg_brushNor = data->avg_brushNor;
+ const Vec3f *brushVelocity = data->brushVelocity;
+
+ BVHTreeFromMesh *treeData = data->treeData;
+
+ const int index = grid->t_index[grid->s_pos[c_index] + id];
+ const int samples = bData->s_num[index];
+ int ss;
+ 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 */
+ if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
+ total_sample = gaussianTotal;
+
+ /* 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};
+ const bool inner_proximity = (brush->flags & MOD_DPAINT_INVERSE_PROX &&
+ brush->collision == MOD_DPAINT_COL_VOLDIST);
+
+ /* hit data */
+ float hitCoord[3];
+ int hitTri = -1;
+
+ /* 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 = BVH_RAYCAST_DIST_MAX;
+ nearest.index = -1;
+ nearest.dist_sq = brush_radius * brush_radius; /* find_nearest uses squared distance */
+
+ /* Check volume collision */
+ if (ELEM(brush->collision, MOD_DPAINT_COL_VOLUME, MOD_DPAINT_COL_VOLDIST)) {
+ BLI_bvhtree_ray_cast(treeData->tree, ray_start, ray_dir, 0.0f, &hit, mesh_tris_spherecast_dp, treeData);
+ if (hit.index != -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 */
+ const int vtri[3] = {
+ mloop[mlooptri[hit.index].tri[0]].v,
+ mloop[mlooptri[hit.index].tri[1]].v,
+ mloop[mlooptri[hit.index].tri[2]].v,
+ };
+ float dot;
+
+ normal_tri_v3(hit.no, mvert[vtri[0]].co, mvert[vtri[1]].co, mvert[vtri[2]].co);
+ dot = dot_v3v3(ray_dir, hit.no);
+
+ /* If ray and hit face normal are facing same direction
+ * hit point is inside a closed mesh. */
+ if (dot >= 0.0f) {
+ const float dist = hit.dist;
+ const int f_index = hit.index;
+
+ /* Also cast a ray in opposite direction to make sure
+ * point is at least surrounded by two brush faces */
+ negate_v3(ray_dir);
+ hit.index = -1;
+ hit.dist = BVH_RAYCAST_DIST_MAX;
+
+ BLI_bvhtree_ray_cast(
+ treeData->tree, ray_start, ray_dir, 0.0f, &hit, mesh_tris_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;
+ hitTri = f_index;
+ }
+ }
+ }
+ }
+
+ /* Check proximity collision */
+ if (ELEM(brush->collision, MOD_DPAINT_COL_DIST, MOD_DPAINT_COL_VOLDIST) &&
+ (!hit_found || (brush->flags & MOD_DPAINT_INVERSE_PROX)))
+ {
+ float proxDist = -1.0f;
+ float hitCo[3] = {0.0f, 0.0f, 0.0f};
+ int tri = 0;
+
+ /* 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)) {
+ BLI_bvhtree_find_nearest(treeData->tree, ray_start, &nearest, mesh_tris_nearest_point_dp, treeData);
+ if (nearest.index != -1) {
+ proxDist = sqrtf(nearest.dist_sq);
+ copy_v3_v3(hitCo, nearest.co);
+ tri = nearest.index;
+ }
+ }
+ 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 */
+ BLI_bvhtree_ray_cast(
+ treeData->tree, ray_start, proj_ray, 0.0f, &hit, mesh_tris_spherecast_dp, treeData);
+ if (hit.index != -1) {
+ proxDist = hit.dist;
+ madd_v3_v3v3fl(hitCo, ray_start, proj_ray, hit.dist); /* Calculate final hit coordinates */
+ tri = hit.index;
+ }
+ }
+
+ /* 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;
+
+ hit_found = HIT_PROXIMITY;
+
+ /* if no volume hit, use prox point face info */
+ if (hitTri == -1) {
+ copy_v3_v3(hitCoord, hitCo);
+ hitTri = tri;
+ }
+ }
+ }
+
+ /* 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;
+ }
+
+ /* 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;
+ }
+
+ sampleStrength *= sample_factor;
+ }
+ else {
+ continue;
+ }
+
+ /* velocity brush, only do on main sample */
+ if (brush->flags & MOD_DPAINT_USES_VELOCITY && ss == 0 && brushVelocity) {
+ float weights[4];
+ float brushPointVelocity[3];
+ float velocity[3];
+
+ const int v1 = mloop[mlooptri[hitTri].tri[0]].v;
+ const int v2 = mloop[mlooptri[hitTri].tri[1]].v;
+ const int v3 = mloop[mlooptri[hitTri].tri[2]].v;
+
+ /* calculate barycentric weights for hit point */
+ interp_weights_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, hitCoord);
+
+ /* simple check based on brush surface velocity,
+ * todo: perhaps implement something that handles volume movement as well */
+
+ /* 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 = normalize_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);
+ bData->brush_velocity[index * 4 + 3] = velocity_val;
+ }
+ }
+
+ /*
+ * 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, hitTri, 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];
+ }
+ }
+
+ /* Add AA sample */
+ paintColor[0] += sampleColor[0];
+ paintColor[1] += sampleColor[1];
+ paintColor[2] += sampleColor[2];
+ sampleStrength *= alpha_factor;
+ numOfHits++;
+ }
+
+ /* apply sample strength */
+ brushStrength += sampleStrength;
+ } // end supersampling
+
+
+ /* if any sample was inside paint range */
+ if (brushStrength > 0.0f || depth > 0.0f) {
+ /* apply supersampling results */
+ if (samples > 1) {
+ brushStrength /= total_sample;
+ }
+ CLAMP(brushStrength, 0.0f, 1.0f);
+
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ /* Get final pixel color and alpha */
+ paintColor[0] /= numOfHits;
+ paintColor[1] /= numOfHits;
+ paintColor[2] /= numOfHits;
+ }
+ /* get final object space depth */
+ else if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
+ depth /= bData->bNormal[index].normal_scale * total_sample;
+ }
+
+ dynamicPaint_updatePointData(surface, index, brush, paintColor, brushStrength, depth, velocity_val, timescale);
+ }
+}
+
static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
DynamicPaintBrushSettings *brush,
Object *brushOb,
@@ -3121,11 +3776,13 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
if (brush->flags & MOD_DPAINT_USES_VELOCITY)
dynamicPaint_brushMeshCalculateVelocity(scene, brushOb, brush, &brushVelocity, timescale);
- if (!brush->dm) return 0;
+ if (!brush->dm)
+ return 0;
+
{
BVHTreeFromMesh treeData = {NULL};
float avg_brushNor[3] = {0.0f};
- float brush_radius = brush->paint_distance * surface->radius_scale;
+ const float brush_radius = brush->paint_distance * surface->radius_scale;
int numOfVerts;
int ii;
Bounds3D mesh_bb = {0};
@@ -3172,305 +3829,25 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
/* loop through space partitioning grid */
for (c_index = 0; c_index < total_cells; c_index++) {
- int id;
-
/* check grid cell bounding box */
- if (!grid->s_num[c_index] || !meshBrush_boundsIntersect(&grid->bounds[c_index], &mesh_bb, brush, brush_radius))
+ if (!grid->s_num[c_index] ||
+ !meshBrush_boundsIntersect(&grid->bounds[c_index], &mesh_bb, brush, brush_radius))
+ {
continue;
+ }
/* loop through cell points and process brush */
-#pragma omp parallel for schedule(static)
- for (id = 0; id < grid->s_num[c_index]; id++) {
- int index = grid->t_index[grid->s_pos[c_index] + id];
- 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 */
- if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
- total_sample = gaussianTotal;
-
- /* 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 hitTri = -1;
-
- /* 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 = BVH_RAYCAST_DIST_MAX;
- nearest.index = -1;
- nearest.dist_sq = 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_tris_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 */
- const int vtri[3] = {
- mloop[mlooptri[hit.index].tri[0]].v,
- mloop[mlooptri[hit.index].tri[1]].v,
- mloop[mlooptri[hit.index].tri[2]].v,
- };
- float dot;
-
- normal_tri_v3(hit.no, mvert[vtri[0]].co, mvert[vtri[1]].co, mvert[vtri[2]].co);
- dot = dot_v3v3(ray_dir, hit.no);
-
- /* 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
- * point is at least surrounded by two brush faces */
- negate_v3(ray_dir);
- hit.index = -1;
- hit.dist = BVH_RAYCAST_DIST_MAX;
-
- BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_dir, 0.0f, &hit, mesh_tris_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;
- hitTri = f_index;
- }
- }
- }
-
- /* Check proximity collision */
- if ((brush->collision == MOD_DPAINT_COL_DIST || brush->collision == MOD_DPAINT_COL_VOLDIST) &&
- (!hit_found || (brush->flags & MOD_DPAINT_INVERSE_PROX)))
- {
- float proxDist = -1.0f;
- float hitCo[3] = {0.0f, 0.0f, 0.0f};
- int tri = 0;
-
- /* 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_tris_nearest_point_dp, &treeData) != -1) {
- proxDist = sqrtf(nearest.dist_sq);
- copy_v3_v3(hitCo, nearest.co);
- tri = nearest.index;
- }
- }
- 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_tris_spherecast_dp, &treeData) != -1) {
- proxDist = hit.dist;
- madd_v3_v3v3fl(hitCo, ray_start, proj_ray, hit.dist); /* Calculate final hit coordinates */
- tri = hit.index;
- }
- }
-
- /* 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;
-
- hit_found = HIT_PROXIMITY;
-
- /* if no volume hit, use prox point face info */
- if (hitTri == -1) {
- copy_v3_v3(hitCoord, hitCo);
- hitTri = tri;
- }
- }
- }
-
- /* 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;
- }
-
- /* 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;
- }
-
- sampleStrength *= sample_factor;
- }
- else {
- continue;
- }
-
- /* 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];
-
- v1 = mloop[mlooptri[hitTri].tri[0]].v;
- v2 = mloop[mlooptri[hitTri].tri[1]].v;
- v3 = mloop[mlooptri[hitTri].tri[2]].v;
-
- /* calculate barycentric weights for hit point */
- interp_weights_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, hitCoord);
-
- /* simple check based on brush surface velocity,
- * todo: perhaps implement something that handles volume movement as well */
-
- /* 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;
- }
- }
-
- /*
- * 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, hitTri, 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];
- }
- }
-
- /* Add AA sample */
- paintColor[0] += sampleColor[0];
- paintColor[1] += sampleColor[1];
- paintColor[2] += sampleColor[2];
- sampleStrength *= alpha_factor;
- numOfHits++;
- }
-
- /* apply sample strength */
- brushStrength += sampleStrength;
- } // end supersampling
-
-
- /* if any sample was inside paint range */
- if (brushStrength > 0.0f || depth > 0.0f) {
-
- /* apply supersampling results */
- if (samples > 1) {
- brushStrength /= total_sample;
- }
- CLAMP(brushStrength, 0.0f, 1.0f);
-
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- /* Get final pixel color and alpha */
- paintColor[0] /= numOfHits;
- paintColor[1] /= numOfHits;
- paintColor[2] /= numOfHits;
- }
- /* get final object space depth */
- else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
- surface->type == MOD_DPAINT_SURFACE_T_WAVE)
- {
- depth /= bData->bNormal[index].normal_scale * total_sample;
- }
-
- dynamicPaint_updatePointData(surface, index, brush, paintColor, brushStrength, depth, velocity_val, timescale);
- }
- }
+ DynamicPaintPaintData data = {
+ .surface = surface,
+ .brush = brush, .brushOb = brushOb, .bMats = bMats,
+ .scene = scene, .timescale = timescale, .c_index = c_index,
+ .dm = dm, .mvert = mvert, .mloop = mloop, .mlooptri = mlooptri,
+ .brush_radius = brush_radius, .avg_brushNor = avg_brushNor, .brushVelocity = brushVelocity,
+ .treeData = &treeData
+ };
+ BLI_task_parallel_range_ex(0, grid->s_num[c_index], &data, NULL, 0,
+ dynamic_paint_paint_mesh_cell_point_cb_ex,
+ grid->s_num[c_index] > 250, true);
}
}
}
@@ -3488,110 +3865,142 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
}
/* paint a single point of defined proximity radius to the surface */
-static int dynamicPaint_paintSinglePoint(DynamicPaintSurface *surface, float *pointCoord, DynamicPaintBrushSettings *brush,
- Object *brushOb, BrushMaterials *bMats, Scene *scene, float timescale)
+static void dynamic_paint_paint_single_point_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int index, const int UNUSED(threadid))
{
- int index;
- float brush_radius = brush->paint_distance * surface->radius_scale;
- PaintSurfaceData *sData = surface->data;
- PaintBakeData *bData = sData->bData;
- Vec3f brushVel;
+ const DynamicPaintPaintData *data = userdata;
- if (brush->flags & MOD_DPAINT_USES_VELOCITY)
- dynamicPaint_brushObjectCalculateVelocity(scene, brushOb, &brushVel, timescale);
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const PaintBakeData *bData = sData->bData;
- /*
- * Loop through every surface point
- */
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- float distance = len_v3v3(pointCoord, bData->realCoord[bData->s_pos[index]].v);
- float colorband[4] = {0.0f};
- float strength;
+ const DynamicPaintBrushSettings *brush = data->brush;
+ Object *brushOb = data->brushOb;
+ const BrushMaterials *bMats = data->bMats;
- if (distance > brush_radius) continue;
+ const Scene *scene = data->scene;
+ const float timescale = data->timescale;
- /* Smooth range or color ramp */
- if (brush->proximity_falloff == MOD_DPAINT_PRFALL_SMOOTH ||
- brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP)
- {
- strength = 1.0f - distance / brush_radius;
- CLAMP(strength, 0.0f, 1.0f);
- }
- else {
- strength = 1.0f;
- }
+ const MVert *mvert = data->mvert;
+ const float brush_radius = data->brush_radius;
+ const Vec3f *brushVelocity = data->brushVelocity;
- if (strength >= 0.001f) {
- float paintColor[3] = {0.0f};
- float depth = 0.0f;
- float velocity_val = 0.0f;
+ float *pointCoord = data->pointCoord;
- /* material */
- if (brush_usesMaterial(brush, scene)) {
- float alpha_factor = 1.0f;
- float hit_coord[3];
- MVert *mvert = brush->dm->getVertArray(brush->dm);
- /* use dummy coord of first vertex */
- copy_v3_v3(hit_coord, mvert[0].co);
- mul_m4_v3(brushOb->obmat, hit_coord);
-
- dynamicPaint_doMaterialTex(bMats, paintColor, &alpha_factor, brushOb, bData->realCoord[bData->s_pos[index]].v, hit_coord, 0, brush->dm);
- }
+ const float distance = len_v3v3(pointCoord, bData->realCoord[bData->s_pos[index]].v);
+ float colorband[4] = {0.0f};
+ float strength;
- /* color ramp */
- if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP && do_colorband(brush->paint_ramp, (1.0f - strength), colorband))
- strength = colorband[3];
+ if (distance > brush_radius)
+ return;
- if (brush->flags & MOD_DPAINT_USES_VELOCITY) {
- float velocity[3];
+ /* Smooth range or color ramp */
+ if (brush->proximity_falloff == MOD_DPAINT_PRFALL_SMOOTH ||
+ brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP)
+ {
+ strength = 1.0f - distance / brush_radius;
+ CLAMP(strength, 0.0f, 1.0f);
+ }
+ else {
+ strength = 1.0f;
+ }
- /* substract canvas point velocity */
- if (bData->velocity) {
- sub_v3_v3v3(velocity, brushVel.v, bData->velocity[index].v);
- }
- else {
- copy_v3_v3(velocity, brushVel.v);
- }
- velocity_val = len_v3(velocity);
+ if (strength >= 0.001f) {
+ float paintColor[3] = {0.0f};
+ float depth = 0.0f;
+ float velocity_val = 0.0f;
- /* store brush velocity for smudge */
- 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;
- }
+ /* material */
+ if (brush_usesMaterial(brush, scene)) {
+ float alpha_factor = 1.0f;
+ float hit_coord[3];
+ /* use dummy coord of first vertex */
+ mul_v3_m4v3(hit_coord, brushOb->obmat, mvert[0].co);
+
+ dynamicPaint_doMaterialTex(bMats, paintColor, &alpha_factor, brushOb,
+ bData->realCoord[bData->s_pos[index]].v, hit_coord, 0, brush->dm);
+ }
+
+ /* color ramp */
+ if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
+ do_colorband(brush->paint_ramp, (1.0f - strength), colorband))
+ {
+ strength = colorband[3];
+ }
+
+ if (brush->flags & MOD_DPAINT_USES_VELOCITY) {
+ float velocity[3];
+
+ /* substract canvas point velocity */
+ if (bData->velocity) {
+ sub_v3_v3v3(velocity, brushVelocity->v, bData->velocity[index].v);
+ }
+ else {
+ copy_v3_v3(velocity, brushVelocity->v);
}
+ velocity_val = len_v3(velocity);
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
- !(brush->flags & MOD_DPAINT_RAMP_ALPHA))
- {
- paintColor[0] = colorband[0];
- paintColor[1] = colorband[1];
- paintColor[2] = colorband[2];
- }
- else {
- if (!brush_usesMaterial(brush, scene)) {
- paintColor[0] = brush->r;
- paintColor[1] = brush->g;
- paintColor[2] = brush->b;
- }
- }
+ /* store brush velocity for smudge */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT &&
+ brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity)
+ {
+ mul_v3_v3fl(&bData->brush_velocity[index * 4], velocity, 1.0f / velocity_val);
+ bData->brush_velocity[index * 4 + 3] = velocity_val;
}
- else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
- surface->type == MOD_DPAINT_SURFACE_T_WAVE)
+ }
+
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
+ !(brush->flags & MOD_DPAINT_RAMP_ALPHA))
{
- /* get displace depth */
- float disp_intersect = (1.0f - sqrtf((brush_radius - distance) / brush_radius)) * brush_radius;
- depth = (brush_radius - disp_intersect) / bData->bNormal[index].normal_scale;
- if (depth < 0.0f) depth = 0.0f;
+ paintColor[0] = colorband[0];
+ paintColor[1] = colorband[1];
+ paintColor[2] = colorband[2];
+ }
+ else {
+ if (!brush_usesMaterial(brush, scene)) {
+ paintColor[0] = brush->r;
+ paintColor[1] = brush->g;
+ paintColor[2] = brush->b;
+ }
}
- dynamicPaint_updatePointData(surface, index, brush, paintColor, strength, depth, velocity_val, timescale);
}
+ else if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
+ /* get displace depth */
+ const float disp_intersect = (1.0f - sqrtf((brush_radius - distance) / brush_radius)) * brush_radius;
+ depth = max_ff(0.0f, (brush_radius - disp_intersect) / bData->bNormal[index].normal_scale);
+ }
+ dynamicPaint_updatePointData(surface, index, brush, paintColor, strength, depth, velocity_val, timescale);
}
+}
+
+static int dynamicPaint_paintSinglePoint(
+ DynamicPaintSurface *surface, float *pointCoord, DynamicPaintBrushSettings *brush,
+ Object *brushOb, BrushMaterials *bMats, Scene *scene, float timescale)
+{
+ PaintSurfaceData *sData = surface->data;
+ float brush_radius = brush->paint_distance * surface->radius_scale;
+ Vec3f brushVel;
+
+ if (brush->flags & MOD_DPAINT_USES_VELOCITY)
+ dynamicPaint_brushObjectCalculateVelocity(scene, brushOb, &brushVel, timescale);
+
+ const MVert *mvert = brush->dm->getVertArray(brush->dm);
+
+ /*
+ * Loop through every surface point
+ */
+ DynamicPaintPaintData data = {
+ .surface = surface,
+ .brush = brush, .brushOb = brushOb, .bMats = bMats,
+ .scene = scene, .timescale = timescale,
+ .mvert = mvert,
+ .brush_radius = brush_radius, .brushVelocity = &brushVel,
+ .pointCoord = pointCoord,
+ };
+ BLI_task_parallel_range_ex(0, sData->total_points, &data, NULL, 0,
+ dynamic_paint_paint_single_point_cb_ex,
+ sData->total_points > 1000, true);
return 1;
}
@@ -3602,57 +4011,68 @@ static int dynamicPaint_paintSinglePoint(DynamicPaintSurface *surface, float *po
/*
* Calculate current frame distances and directions for adjacency data
*/
-static void dynamicPaint_prepareAdjacencyData(DynamicPaintSurface *surface, int force_init)
+
+static void dynamic_paint_prepare_adjacency_cb(void *userdata, const int index)
+{
+ PaintSurfaceData *sData = userdata;
+ PaintBakeData *bData = sData->bData;
+ BakeAdjPoint *bNeighs = bData->bNeighs;
+ PaintAdjData *adj_data = sData->adj_data;
+ Vec3f *realCoord = bData->realCoord;
+
+ const int num_neighs = adj_data->n_num[index];
+
+ for (int i = 0; i < num_neighs; i++) {
+ const int n_index = adj_data->n_index[index] + i;
+ const int t_index = adj_data->n_target[n_index];
+
+ /* dir vec */
+ sub_v3_v3v3(bNeighs[n_index].dir, realCoord[bData->s_pos[t_index]].v, realCoord[bData->s_pos[index]].v);
+ /* dist */
+ bNeighs[n_index].dist = normalize_v3(bNeighs[n_index].dir);
+ }
+}
+
+static void dynamicPaint_prepareAdjacencyData(DynamicPaintSurface *surface, const bool force_init)
{
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
BakeAdjPoint *bNeighs;
PaintAdjData *adj_data = sData->adj_data;
- Vec3f *realCoord = bData->realCoord;
- int index;
- if ((!surface_usesAdjDistance(surface) && !force_init) || !sData->adj_data) return;
+ int index;
- if (bData->bNeighs) MEM_freeN(bData->bNeighs);
- bNeighs = bData->bNeighs = MEM_mallocN(sData->adj_data->total_targets * sizeof(struct BakeAdjPoint), "PaintEffectBake");
- if (!bNeighs) return;
+ if ((!surface_usesAdjDistance(surface) && !force_init) || !sData->adj_data)
+ return;
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- int i;
- int numOfNeighs = adj_data->n_num[index];
+ if (bData->bNeighs)
+ MEM_freeN(bData->bNeighs);
+ bNeighs = bData->bNeighs = MEM_mallocN(sData->adj_data->total_targets * sizeof(*bNeighs), "PaintEffectBake");
+ if (!bNeighs)
+ return;
- for (i = 0; i < numOfNeighs; i++) {
- int n_index = adj_data->n_index[index] + i;
- int t_index = adj_data->n_target[n_index];
-
- /* dir vec */
- sub_v3_v3v3(bNeighs[n_index].dir, realCoord[bData->s_pos[t_index]].v, realCoord[bData->s_pos[index]].v);
- /* dist */
- bNeighs[n_index].dist = len_v3(bNeighs[n_index].dir);
- /* normalize dir */
- if (bNeighs[n_index].dist) mul_v3_fl(bNeighs[n_index].dir, 1.0f / bNeighs[n_index].dist);
- }
- }
+ BLI_task_parallel_range(
+ 0, sData->total_points, sData, dynamic_paint_prepare_adjacency_cb, sData->total_points > 1000);
- /* calculate average values (single thread) */
- bData->average_dist = 0.0f;
+ /* calculate average values (single thread).
+ * Note: tried to put this in threaded callback (using _finalize feature), but gave ~30% slower result! */
+ bData->average_dist = 0.0;
for (index = 0; index < sData->total_points; index++) {
- int i;
int numOfNeighs = adj_data->n_num[index];
- for (i = 0; i < numOfNeighs; i++) {
+ for (int i = 0; i < numOfNeighs; i++) {
bData->average_dist += (double)bNeighs[adj_data->n_index[index] + i].dist;
}
}
- bData->average_dist /= adj_data->total_targets;
+ bData->average_dist /= adj_data->total_targets;
}
/* find two adjacency points (closest_id) and influence (closest_d) to move paint towards when affected by a force */
-static void surface_determineForceTargetPoints(PaintSurfaceData *sData, int index, float force[3], float closest_d[2], int closest_id[2])
+static void surface_determineForceTargetPoints(
+ const PaintSurfaceData *sData, const int index, const float force[3], float closest_d[2], int closest_id[2])
{
BakeAdjPoint *bNeighs = sData->bData->bNeighs;
- int numOfNeighs = sData->adj_data->n_num[index];
+ const int numOfNeighs = sData->adj_data->n_num[index];
int i;
closest_id[0] = closest_id[1] = -1;
@@ -3660,35 +4080,42 @@ static void surface_determineForceTargetPoints(PaintSurfaceData *sData, int inde
/* find closest neigh */
for (i = 0; i < numOfNeighs; i++) {
- int n_index = sData->adj_data->n_index[index] + i;
- float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
+ const int n_index = sData->adj_data->n_index[index] + i;
+ const float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
- if (dir_dot > closest_d[0] && dir_dot > 0.0f) { closest_d[0] = dir_dot; closest_id[0] = n_index; }
+ if (dir_dot > closest_d[0] && dir_dot > 0.0f) {
+ closest_d[0] = dir_dot;
+ closest_id[0] = n_index;
+ }
}
- if (closest_d[0] < 0.0f) return;
+ if (closest_d[0] < 0.0f)
+ return;
/* find second closest neigh */
for (i = 0; i < numOfNeighs; i++) {
- int n_index = sData->adj_data->n_index[index] + i;
- float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
- float closest_dot = dot_v3v3(bNeighs[n_index].dir, bNeighs[closest_id[0]].dir);
+ const int n_index = sData->adj_data->n_index[index] + i;
- if (n_index == closest_id[0]) continue;
+ if (n_index == closest_id[0])
+ continue;
+
+ const float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
+ const float closest_dot = dot_v3v3(bNeighs[n_index].dir, bNeighs[closest_id[0]].dir);
/* only accept neighbor at "other side" of the first one in relation to force dir
* so make sure angle between this and closest neigh is greater than first angle */
if (dir_dot > closest_d[1] && closest_dot < closest_d[0] && dir_dot > 0.0f) {
- closest_d[1] = dir_dot; closest_id[1] = n_index;
+ closest_d[1] = dir_dot;
+ closest_id[1] = n_index;
}
}
- /* if two valid neighs found, calculate how force effect is divided
- * evenly between them (so that d[0]+d[1] = 1.0)*/
+ /* if two valid neighs found, calculate how force effect is divided evenly between them
+ * (so that d[0] + d[1] = 1.0) */
if (closest_id[1] != -1) {
float force_proj[3];
float tangent[3];
- float neigh_diff = acosf(dot_v3v3(bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir));
+ const float neigh_diff = acosf(dot_v3v3(bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir));
float force_intersect;
float temp;
@@ -3725,12 +4152,13 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus
int index, steps, step;
float eff_scale, max_velocity = 0.0f;
- if (!sData->adj_data) return;
+ if (!sData->adj_data)
+ return;
/* find max velocity */
for (index = 0; index < sData->total_points; index++) {
float vel = bData->brush_velocity[index * 4 + 3];
- if (vel > max_velocity) max_velocity = vel;
+ CLAMP_MIN(max_velocity, vel);
}
steps = (int)ceil(max_velocity / bData->average_dist * timescale);
@@ -3738,7 +4166,6 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus
eff_scale = brush->smudge_strength / (float)steps * timescale;
for (step = 0; step < steps; step++) {
-
for (index = 0; index < sData->total_points; index++) {
int i;
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
@@ -3748,8 +4175,9 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus
int closest_id[2];
float closest_d[2];
- if (!smudge_str) continue;
-
+ if (!smudge_str)
+ continue;
+
/* get force affect points */
surface_determineForceTargetPoints(sData, index, &bData->brush_velocity[index * 4], closest_d, closest_id);
@@ -3762,7 +4190,8 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus
PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[sData->adj_data->n_target[n_index]];
/* just skip if angle is too extreme */
- if (dir_dot <= 0.0f) continue;
+ if (dir_dot <= 0.0f)
+ continue;
dir_factor = dir_dot * speed_scale;
CLAMP_MAX(dir_factor, brush->smudge_strength);
@@ -3781,11 +4210,83 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus
}
}
+typedef struct DynamicPaintEffectData {
+ const DynamicPaintSurface *surface;
+ Scene *scene;
+
+ float *force;
+ ListBase *effectors;
+ const void *prevPoint;
+ const float eff_scale;
+
+ uint8_t *point_locks;
+
+ const float wave_speed;
+ const float wave_scale;
+ const float wave_max_slope;
+
+ const float dt;
+ const float min_dist;
+ const float damp_factor;
+ const bool reset_wave;
+} DynamicPaintEffectData;
+
/*
* Prepare data required by effects for current frame.
* Returns number of steps required
*/
-static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *scene, Object *ob, float **force, float timescale)
+static void dynamic_paint_prepare_effect_cb(void *userdata, const int index)
+{
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const PaintBakeData *bData = sData->bData;
+ Vec3f *realCoord = bData->realCoord;
+
+ Scene *scene = data->scene;
+
+ float *force = data->force;
+ ListBase *effectors = data->effectors;
+
+ float forc[3] = {0};
+ float vel[3] = {0};
+
+ /* apply force fields */
+ if (effectors) {
+ EffectedPoint epoint;
+ pd_point_from_loc(scene, realCoord[bData->s_pos[index]].v, vel, index, &epoint);
+ epoint.vel_to_sec = 1.0f;
+ pdDoEffectors(effectors, NULL, surface->effector_weights, &epoint, forc, NULL);
+ }
+
+ /* if global gravity is enabled, add it too */
+ if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY)
+ /* also divide by 10 to about match default grav
+ * with default force strength (1.0) */
+ madd_v3_v3fl(forc, scene->physics_settings.gravity,
+ surface->effector_weights->global_gravity * surface->effector_weights->weight[0] / 10.f);
+
+ /* add surface point velocity and acceleration if enabled */
+ if (bData->velocity) {
+ if (surface->drip_vel)
+ madd_v3_v3fl(forc, bData->velocity[index].v, surface->drip_vel * (-1.0f));
+
+ /* acceleration */
+ if (bData->prev_velocity && surface->drip_acc) {
+ float acc[3];
+ copy_v3_v3(acc, bData->velocity[index].v);
+ sub_v3_v3(acc, bData->prev_velocity[index].v);
+ madd_v3_v3fl(forc, acc, surface->drip_acc * (-1.0f));
+ }
+ }
+
+ /* force strength, and normalize force vec */
+ force[index * 4 + 3] = normalize_v3_v3(&force[index * 4], forc);
+}
+
+static int dynamicPaint_prepareEffectStep(
+ DynamicPaintSurface *surface, Scene *scene, Object *ob, float **force, float timescale)
{
double average_force = 0.0f;
float shrink_speed = 0.0f, spread_speed = 0.0f;
@@ -3793,60 +4294,24 @@ static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *s
int steps;
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
- Vec3f *realCoord = bData->realCoord;
- int index;
/* Init force data if required */
if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
- float vel[3] = {0};
ListBase *effectors = pdInitEffectors(scene, ob, surface->effector_weights, true);
/* allocate memory for force data (dir vector + strength) */
*force = MEM_mallocN(sData->total_points * 4 * sizeof(float), "PaintEffectForces");
if (*force) {
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- float forc[3] = {0};
-
- /* apply force fields */
- if (effectors) {
- EffectedPoint epoint;
- pd_point_from_loc(scene, realCoord[bData->s_pos[index]].v, vel, index, &epoint);
- epoint.vel_to_sec = 1.0f;
- pdDoEffectors(effectors, NULL, surface->effector_weights, &epoint, forc, NULL);
- }
-
- /* if global gravity is enabled, add it too */
- if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY)
- /* also divide by 10 to about match default grav
- * with default force strength (1.0) */
- madd_v3_v3fl(forc, scene->physics_settings.gravity,
- surface->effector_weights->global_gravity * surface->effector_weights->weight[0] / 10.f);
-
- /* add surface point velocity and acceleration if enabled */
- if (bData->velocity) {
- if (surface->drip_vel)
- madd_v3_v3fl(forc, bData->velocity[index].v, surface->drip_vel * (-1.0f));
-
- /* acceleration */
- if (bData->prev_velocity && surface->drip_acc) {
- float acc[3];
- copy_v3_v3(acc, bData->velocity[index].v);
- sub_v3_v3(acc, bData->prev_velocity[index].v);
- madd_v3_v3fl(forc, acc, surface->drip_acc * (-1.0f));
- }
- }
-
- /* force strength */
- (*force)[index * 4 + 3] = len_v3(forc);
- /* normalize and copy */
- if ((*force)[index * 4 + 3]) mul_v3_fl(forc, 1.0f / (*force)[index * 4 + 3]);
- copy_v3_v3(&((*force)[index * 4]), forc);
- }
+ DynamicPaintEffectData data = {
+ .surface = surface, .scene = scene,
+ .force = *force, .effectors = effectors,
+ };
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_prepare_effect_cb, sData->total_points > 1000);
/* calculate average values (single thread) */
- for (index = 0; index < sData->total_points; index++) {
+ for (int index = 0; index < sData->total_points; index++) {
average_force += (*force)[index * 4 + 3];
}
average_force /= sData->total_points;
@@ -3866,7 +4331,7 @@ static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *s
fastest_effect = max_fff(spread_speed, shrink_speed, average_force);
avg_dist = bData->average_dist * CANVAS_REL_SIZE / getSurfaceDimension(sData);
- steps = (int)ceil(1.5f * EFF_MOVEMENT_PER_FRAME * fastest_effect / avg_dist * timescale);
+ steps = (int)ceilf(1.5f * EFF_MOVEMENT_PER_FRAME * fastest_effect / avg_dist * timescale);
CLAMP(steps, 1, 20);
return steps;
@@ -3875,166 +4340,337 @@ static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *s
/**
* Processes active effect step.
*/
-static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, float *force, PaintPoint *prevPoint, float timescale, float steps)
+static void dynamic_paint_effect_spread_cb(void *userdata, const int index)
{
- PaintSurfaceData *sData = surface->data;
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+
+ const int numOfNeighs = sData->adj_data->n_num[index];
BakeAdjPoint *bNeighs = sData->bData->bNeighs;
- float distance_scale = getSurfaceDimension(sData) / CANVAS_REL_SIZE;
- int index;
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ const PaintPoint *prevPoint = data->prevPoint;
+ const float eff_scale = data->eff_scale;
+
+ const int *n_index = sData->adj_data->n_index;
+ const int *n_target = sData->adj_data->n_target;
+
+ /* Loop through neighboring points */
+ for (int i = 0; i < numOfNeighs; i++) {
+ const int n_idx = n_index[index] + i;
+ float w_factor;
+ const PaintPoint *pPoint_prev = &prevPoint[n_target[n_idx]];
+ const float speed_scale = (bNeighs[n_idx].dist < eff_scale) ? 1.0f : eff_scale / bNeighs[n_idx].dist;
+ const float color_mix = min_fff(pPoint_prev->wetness, pPoint->wetness, 1.0f) * 0.25f * surface->color_spread_speed;
+
+ /* do color mixing */
+ if (color_mix)
+ mixColors(pPoint->e_color, pPoint->e_color[3], pPoint_prev->e_color, pPoint_prev->e_color[3], color_mix);
+
+ /* Only continue if surrounding point has higher wetness */
+ if (pPoint_prev->wetness < pPoint->wetness || pPoint_prev->wetness < MIN_WETNESS)
+ continue;
+
+ w_factor = 1.0f / numOfNeighs * min_ff(pPoint_prev->wetness, 1.0f) * speed_scale;
+ CLAMP(w_factor, 0.0f, 1.0f);
+
+ /* mix new wetness and color */
+ pPoint->wetness = (1.0f - w_factor) * pPoint->wetness + w_factor * pPoint_prev->wetness;
+ pPoint->e_color[3] = mixColors(pPoint->e_color, pPoint->e_color[3],
+ pPoint_prev->e_color, pPoint_prev->e_color[3], w_factor);
+ }
+}
+
+static void dynamic_paint_effect_shrink_cb(void *userdata, const int index)
+{
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+
+ const int numOfNeighs = sData->adj_data->n_num[index];
+ BakeAdjPoint *bNeighs = sData->bData->bNeighs;
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ const PaintPoint *prevPoint = data->prevPoint;
+ const float eff_scale = data->eff_scale;
+ float totalAlpha = 0.0f;
+
+ const int *n_index = sData->adj_data->n_index;
+ const int *n_target = sData->adj_data->n_target;
+
+ /* Loop through neighboring points */
+ for (int i = 0; i < numOfNeighs; i++) {
+ const int n_idx = n_index[index] + i;
+ const float speed_scale = (bNeighs[n_idx].dist < eff_scale) ? 1.0f : eff_scale / bNeighs[n_idx].dist;
+ const PaintPoint *pPoint_prev = &prevPoint[n_target[n_idx]];
+ float a_factor, ea_factor, w_factor;
+
+ totalAlpha += pPoint_prev->e_color[3];
+
+ /* Check if neighboring point has lower alpha,
+ * if so, decrease this point's alpha as well*/
+ if (pPoint->color[3] <= 0.0f && pPoint->e_color[3] <= 0.0f && pPoint->wetness <= 0.0f)
+ continue;
+
+ /* decrease factor for dry paint alpha */
+ a_factor = max_ff((1.0f - pPoint_prev->color[3]) / numOfNeighs * (pPoint->color[3] - pPoint_prev->color[3]) * speed_scale, 0.0f);
+ /* decrease factor for wet paint alpha */
+ ea_factor = max_ff((1.0f - pPoint_prev->e_color[3]) / 8 * (pPoint->e_color[3] - pPoint_prev->e_color[3]) * speed_scale, 0.0f);
+ /* decrease factor for paint wetness */
+ w_factor = max_ff((1.0f - pPoint_prev->wetness) / 8 * (pPoint->wetness - pPoint_prev->wetness) * speed_scale, 0.0f);
+
+ pPoint->color[3] -= a_factor;
+ CLAMP_MIN(pPoint->color[3], 0.0f);
+ pPoint->e_color[3] -= ea_factor;
+ CLAMP_MIN(pPoint->e_color[3], 0.0f);
+ pPoint->wetness -= w_factor;
+ CLAMP_MIN(pPoint->wetness, 0.0f);
+ }
+}
+
+static void dynamic_paint_effect_drip_cb(void *userdata, const int index)
+{
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ BakeAdjPoint *bNeighs = sData->bData->bNeighs;
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ const PaintPoint *prevPoint = data->prevPoint;
+ const PaintPoint *pPoint_prev = &prevPoint[index];
+ const float *force = data->force;
+ const float eff_scale = data->eff_scale;
+
+ const int *n_target = sData->adj_data->n_target;
+
+ uint8_t *point_locks = data->point_locks;
+
+ int closest_id[2];
+ float closest_d[2];
+
+ /* adjust drip speed depending on wetness */
+ float w_factor = pPoint_prev->wetness - 0.025f;
+ if (w_factor <= 0)
+ return;
+ CLAMP(w_factor, 0.0f, 1.0f);
+
+ /* get force affect points */
+ surface_determineForceTargetPoints(sData, index, &force[index * 4], closest_d, closest_id);
+
+ /* Apply movement towards those two points */
+ for (int i = 0; i < 2; i++) {
+ const int n_idx = closest_id[i];
+ if (n_idx != -1 && closest_d[i] > 0.0f) {
+ const float dir_dot = closest_d[i];
+
+ /* just skip if angle is too extreme */
+ if (dir_dot <= 0.0f)
+ continue;
+
+ float dir_factor, a_factor;
+ const float speed_scale = eff_scale * force[index * 4 + 3] / bNeighs[n_idx].dist;
+
+ const unsigned int n_trgt = (unsigned int)n_target[n_idx];
+
+ /* Sort of spinlock, but only for given ePoint.
+ * Since the odds a same ePoint is modified at the same time by several threads is very low, this is
+ * much more eficient than a global spin lock. */
+ const unsigned int pointlock_idx = n_trgt / 8;
+ const uint8_t pointlock_bitmask = 1 << (n_trgt & 7); /* 7 == 0b111 */
+ while (atomic_fetch_and_or_uint8(&point_locks[pointlock_idx], pointlock_bitmask) & pointlock_bitmask);
+
+ PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[n_trgt];
+ const float e_wet = ePoint->wetness;
+
+ dir_factor = min_ff(0.5f, dir_dot * min_ff(speed_scale, 1.0f) * w_factor);
+
+ /* mix new wetness */
+ ePoint->wetness += dir_factor;
+ 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_color[3], pPoint_prev->e_color, pPoint_prev->e_color[3], a_factor);
+ /* dripping is supposed to preserve alpha level */
+ if (pPoint_prev->e_color[3] > ePoint->e_color[3]) {
+ ePoint->e_color[3] += a_factor * pPoint_prev->e_color[3];
+ CLAMP_MAX(ePoint->e_color[3], pPoint_prev->e_color[3]);
+ }
+
+ /* decrease paint wetness on current point */
+ pPoint->wetness -= (ePoint->wetness - e_wet);
+ CLAMP(pPoint->wetness, 0.0f, MAX_WETNESS);
+
+#ifndef NDEBUG
+ uint8_t ret = atomic_fetch_and_and_uint8(&point_locks[pointlock_idx], ~pointlock_bitmask);
+ BLI_assert(ret & pointlock_bitmask);
+#else
+ atomic_fetch_and_and_uint8(&point_locks[pointlock_idx], ~pointlock_bitmask);
+#endif
+ }
+ }
+}
+
+static void dynamicPaint_doEffectStep(
+ DynamicPaintSurface *surface, float *force, PaintPoint *prevPoint, float timescale, float steps)
+{
+ PaintSurfaceData *sData = surface->data;
+
+ const float distance_scale = getSurfaceDimension(sData) / CANVAS_REL_SIZE;
timescale /= steps;
- if (!sData->adj_data) return;
+ if (!sData->adj_data)
+ return;
/*
* Spread Effect
*/
if (surface->effect & MOD_DPAINT_EFFECT_DO_SPREAD) {
- float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->spread_speed * timescale;
+ const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->spread_speed * timescale;
/* Copy current surface to the previous points array to read unmodified values */
memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- int i;
- int numOfNeighs = sData->adj_data->n_num[index];
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
-
- /* Only reads values from the surface copy (prevPoint[]),
- * so this one is thread safe */
-
- /* Loop through neighboring points */
- for (i = 0; i < numOfNeighs; i++) {
- int n_index = sData->adj_data->n_index[index] + i;
- float w_factor;
- PaintPoint *ePoint = &prevPoint[sData->adj_data->n_target[n_index]];
- 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;
-
- /* do color mixing */
- if (color_mix) mixColors(pPoint->e_color, pPoint->e_color[3], ePoint->e_color, ePoint->e_color[3], color_mix);
-
- /* Only continue if surrounding point has higher wetness */
- if (ePoint->wetness < pPoint->wetness || ePoint->wetness < MIN_WETNESS) continue;
-
- w_factor = 1.0f / numOfNeighs * MIN2(ePoint->wetness, 1.0f) * speed_scale;
- CLAMP(w_factor, 0.0f, 1.0f);
-
- /* mix new wetness and color */
- pPoint->wetness = (1.0f - w_factor) * pPoint->wetness + w_factor * ePoint->wetness;
- pPoint->e_color[3] = mixColors(pPoint->e_color, pPoint->e_color[3], ePoint->e_color, ePoint->e_color[3], w_factor);
- }
- }
+ DynamicPaintEffectData data = {
+ .surface = surface, .prevPoint = prevPoint, .eff_scale = eff_scale,
+ };
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_effect_spread_cb, sData->total_points > 1000);
}
/*
* Shrink Effect
*/
if (surface->effect & MOD_DPAINT_EFFECT_DO_SHRINK) {
- float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->shrink_speed * timescale;
+ const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->shrink_speed * timescale;
/* Copy current surface to the previous points array to read unmodified values */
memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- int i;
- int numOfNeighs = sData->adj_data->n_num[index];
- float totalAlpha = 0.0f;
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
-
- 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;
- PaintPoint *ePoint = &prevPoint[sData->adj_data->n_target[n_index]];
- float a_factor, ea_factor, w_factor;
-
- totalAlpha += ePoint->e_color[3];
-
- /* Check if neighboring point has lower alpha,
- * if so, decrease this point's alpha as well*/
- if (pPoint->color[3] <= 0.0f && pPoint->e_color[3] <= 0.0f && pPoint->wetness <= 0.0f) continue;
-
- /* decrease factor for dry paint alpha */
- a_factor = (1.0f - ePoint->color[3]) / numOfNeighs * (pPoint->color[3] - ePoint->color[3]) * speed_scale;
- CLAMP_MIN(a_factor, 0.0f);
- /* decrease factor for wet paint alpha */
- ea_factor = (1.0f - ePoint->e_color[3]) / 8 * (pPoint->e_color[3] - ePoint->e_color[3]) * speed_scale;
- CLAMP_MIN(ea_factor, 0.0f);
- /* decrease factor for paint wetness */
- w_factor = (1.0f - ePoint->wetness) / 8 * (pPoint->wetness - ePoint->wetness) * speed_scale;
- CLAMP_MIN(w_factor, 0.0f);
-
- pPoint->color[3] -= a_factor;
- CLAMP_MIN(pPoint->color[3], 0.0f);
- pPoint->e_color[3] -= ea_factor;
- CLAMP_MIN(pPoint->e_color[3], 0.0f);
- pPoint->wetness -= w_factor;
- CLAMP_MIN(pPoint->wetness, 0.0f);
- }
- }
+ DynamicPaintEffectData data = {
+ .surface = surface, .prevPoint = prevPoint, .eff_scale = eff_scale,
+ };
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_effect_shrink_cb, sData->total_points > 1000);
}
/*
* Drip Effect
*/
if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP && force) {
- float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * timescale / 2.0f;
+ const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * timescale / 2.0f;
+
+ /* Same as BLI_bitmask, but handled atomicaly as 'ePoint' locks. */
+ const size_t point_locks_size = (sData->total_points / 8) + 1;
+ uint8_t *point_locks = MEM_callocN(sizeof(*point_locks) * point_locks_size, __func__);
+
/* Copy current surface to the previous points array to read unmodified values */
memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
- for (index = 0; index < sData->total_points; index++) {
- int i;
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
- PaintPoint *pPoint_prev = &prevPoint[index];
+ DynamicPaintEffectData data = {
+ .surface = surface, .prevPoint = prevPoint,
+ .eff_scale = eff_scale, .force = force,
+ .point_locks = point_locks,
+ };
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_effect_drip_cb, sData->total_points > 1000);
- int closest_id[2];
- float closest_d[2];
+ MEM_freeN(point_locks);
+ }
+}
- /* adjust drip speed depending on wetness */
- float w_factor = pPoint_prev->wetness - 0.025f;
- if (w_factor <= 0) continue;
- CLAMP(w_factor, 0.0f, 1.0f);
+static void dynamic_paint_wave_step_cb(void *userdata, const int index)
+{
+ const DynamicPaintEffectData *data = userdata;
- /* get force affect points */
- surface_determineForceTargetPoints(sData, index, &force[index * 4], closest_d, closest_id);
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ BakeAdjPoint *bNeighs = sData->bData->bNeighs;
+ const PaintWavePoint *prevPoint = data->prevPoint;
- /* Apply movement towards those two points */
- for (i = 0; i < 2; i++) {
- int n_index = closest_id[i];
- if (n_index != -1 && closest_d[i] > 0.0f) {
- float dir_dot = closest_d[i], dir_factor, a_factor;
- 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]];
- float e_wet = ePoint->wetness;
+ const float wave_speed = data->wave_speed;
+ const float wave_scale = data->wave_scale;
+ const float wave_max_slope = data->wave_max_slope;
- /* just skip if angle is too extreme */
- if (dir_dot <= 0.0f) continue;
-
- dir_factor = dir_dot * MIN2(speed_scale, 1.0f) * w_factor;
- CLAMP_MAX(dir_factor, 0.5f);
-
- /* mix new wetness */
- ePoint->wetness += dir_factor;
- 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_color[3], pPoint_prev->e_color, pPoint_prev->e_color[3], a_factor);
- /* dripping is supposed to preserve alpha level */
- if (pPoint_prev->e_color[3] > ePoint->e_color[3]) {
- ePoint->e_color[3] += a_factor * pPoint_prev->e_color[3];
- CLAMP_MAX(ePoint->e_color[3], pPoint_prev->e_color[3]);
- }
+ const float dt = data->dt;
+ const float min_dist = data->min_dist;
+ const float damp_factor = data->damp_factor;
- /* decrease paint wetness on current point */
- pPoint->wetness -= (ePoint->wetness - e_wet);
- CLAMP(pPoint->wetness, 0.0f, MAX_WETNESS);
- }
- }
+ PaintWavePoint *wPoint = &((PaintWavePoint *)sData->type_data)[index];
+ const int numOfNeighs = sData->adj_data->n_num[index];
+ float force = 0.0f, avg_dist = 0.0f, avg_height = 0.0f, avg_n_height = 0.0f;
+ int numOfN = 0, numOfRN = 0;
+
+ if (wPoint->state > 0)
+ return;
+
+ const int *n_index = sData->adj_data->n_index;
+ const int *n_target = sData->adj_data->n_target;
+ const int *adj_flags = sData->adj_data->flags;
+
+ /* calculate force from surrounding points */
+ for (int i = 0; i < numOfNeighs; i++) {
+ const int n_idx = n_index[index] + i;
+ float dist = bNeighs[n_idx].dist * wave_scale;
+ const PaintWavePoint *tPoint = &prevPoint[n_target[n_idx]];
+
+ if (!dist || tPoint->state > 0)
+ continue;
+
+ CLAMP_MIN(dist, min_dist);
+ avg_dist += dist;
+ numOfN++;
+
+ /* count average height for edge points for open borders */
+ if (!(adj_flags[n_target[n_idx]] & ADJ_ON_MESH_EDGE)) {
+ avg_n_height += tPoint->height;
+ numOfRN++;
+ }
+
+ force += (tPoint->height - wPoint->height) / (dist * dist);
+ avg_height += tPoint->height;
+ }
+ avg_dist = (numOfN) ? avg_dist / numOfN : 0.0f;
+
+ if (surface->flags & MOD_DPAINT_WAVE_OPEN_BORDERS && adj_flags[index] & ADJ_ON_MESH_EDGE) {
+ /* if open borders, apply a fake height to keep waves going on */
+ 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);
+ }
+ /* else do wave eq */
+ else {
+ /* add force towards zero height based on average dist */
+ if (avg_dist)
+ force += (0.0f - wPoint->height) * surface->wave_spring / (avg_dist * avg_dist) / 2.0f;
+
+ /* change point velocity */
+ wPoint->velocity += force * dt * wave_speed * wave_speed;
+ /* damping */
+ wPoint->velocity *= damp_factor;
+ /* and new height */
+ wPoint->height += wPoint->velocity * dt;
+
+ /* limit wave slope steepness */
+ if (wave_max_slope && avg_dist) {
+ const float max_offset = wave_max_slope * avg_dist;
+ const float offset = (numOfN) ? (avg_height / numOfN - wPoint->height) : 0.0f;
+ if (offset > max_offset)
+ wPoint->height += offset - max_offset;
+ else if (offset < -max_offset)
+ wPoint->height += offset + max_offset;
}
}
+
+ if (data->reset_wave) {
+ /* if there wasnt any brush intersection, clear isect height */
+ if (wPoint->state == DPAINT_WAVE_NONE) {
+ wPoint->brush_isect = 0.0f;
+ }
+ wPoint->state = DPAINT_WAVE_NONE;
+ }
}
static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescale)
@@ -4044,15 +4680,16 @@ static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescal
int index;
int steps, ss;
float dt, min_dist, damp_factor;
- float wave_speed = surface->wave_speed;
- float wave_max_slope = (surface->wave_smoothness >= 0.01f) ? (0.5f / surface->wave_smoothness) : 0.0f;
+ const float wave_speed = surface->wave_speed;
+ const float wave_max_slope = (surface->wave_smoothness >= 0.01f) ? (0.5f / surface->wave_smoothness) : 0.0f;
double average_dist = 0.0f;
const float canvas_size = getSurfaceDimension(sData);
- float wave_scale = CANVAS_REL_SIZE / canvas_size;
+ const float wave_scale = CANVAS_REL_SIZE / canvas_size;
/* allocate memory */
PaintWavePoint *prevPoint = MEM_mallocN(sData->total_points * sizeof(PaintWavePoint), "Temp previous points for wave simulation");
- if (!prevPoint) return;
+ if (!prevPoint)
+ return;
/* calculate average neigh distance (single thread) */
for (index = 0; index < sData->total_points; index++) {
@@ -4076,170 +4713,120 @@ static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescal
damp_factor = pow((1.0f - surface->wave_damping), timescale * surface->wave_timescale);
for (ss = 0; ss < steps; ss++) {
-
/* copy previous frame data */
memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(PaintWavePoint));
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- PaintWavePoint *wPoint = &((PaintWavePoint *)sData->type_data)[index];
- int numOfNeighs = sData->adj_data->n_num[index];
- float force = 0.0f, avg_dist = 0.0f, avg_height = 0.0f, avg_n_height = 0.0f;
- int numOfN = 0, numOfRN = 0;
- int i;
-
- if (wPoint->state > 0) continue;
+ DynamicPaintEffectData data = {
+ .surface = surface, .prevPoint = prevPoint,
+ .wave_speed = wave_speed, .wave_scale = wave_scale, .wave_max_slope = wave_max_slope,
+ .dt = dt, .min_dist = min_dist, .damp_factor = damp_factor, .reset_wave = (ss == steps - 1),
+ };
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_wave_step_cb, sData->total_points > 1000);
+ }
- /* calculate force from surrounding points */
- for (i = 0; i < numOfNeighs; i++) {
- int n_index = sData->adj_data->n_index[index] + i;
- float dist = bNeighs[n_index].dist * wave_scale;
- PaintWavePoint *tPoint = &prevPoint[sData->adj_data->n_target[n_index]];
+ MEM_freeN(prevPoint);
+}
- if (!dist || tPoint->state > 0) continue;
- if (dist < min_dist) dist = min_dist;
- avg_dist += dist;
- numOfN++;
+/* Do dissolve and fading effects */
+static bool dynamic_paint_surface_needs_dry_dissolve(DynamicPaintSurface *surface)
+{
+ return (((surface->type == MOD_DPAINT_SURFACE_T_PAINT) &&
+ (surface->flags & (MOD_DPAINT_USE_DRYING | MOD_DPAINT_DISSOLVE))) ||
+ (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WEIGHT) &&
+ (surface->flags & MOD_DPAINT_DISSOLVE)));
+}
- /* 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)) {
- avg_n_height += tPoint->height;
- numOfRN++;
- }
+typedef struct DynamicPaintDissolveDryData {
+ const DynamicPaintSurface *surface;
+ const float timescale;
+} DynamicPaintDissolveDryData;
- force += (tPoint->height - wPoint->height) / (dist * dist);
- avg_height += tPoint->height;
- }
- avg_dist = (numOfN) ? avg_dist / numOfN : 0.0f;
+static void dynamic_paint_surface_pre_step_cb(void *userdata, const int index)
+{
+ const DynamicPaintDissolveDryData *data = userdata;
- if (surface->flags & MOD_DPAINT_WAVE_OPEN_BORDERS &&
- sData->adj_data->flags[index] & ADJ_ON_MESH_EDGE)
- {
- /* if open borders, apply a fake height to keep waves going on */
- 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);
- }
- /* else do wave eq */
- else {
- /* add force towards zero height based on average dist */
- if (avg_dist)
- force += (0.0f - wPoint->height) * surface->wave_spring / (avg_dist * avg_dist) / 2.0f;
-
- /* change point velocity */
- wPoint->velocity += force * dt * wave_speed * wave_speed;
- /* damping */
- wPoint->velocity *= damp_factor;
- /* and new height */
- wPoint->height += wPoint->velocity * dt;
-
- /* 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;
- }
- }
- }
- }
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const float timescale = data->timescale;
- /* reset state */
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- PaintWavePoint *wPoint = &((PaintWavePoint *)sData->type_data)[index];
- /* if there wasnt any brush intersection, clear isect height */
- if (wPoint->state == DPAINT_WAVE_NONE) {
- wPoint->brush_isect = 0.0f;
- }
- wPoint->state = DPAINT_WAVE_NONE;
- }
+ /* Do drying dissolve effects */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ /* drying */
+ 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;
+
+ value_dissolve(&pPoint->wetness, surface->dry_speed, timescale,
+ (surface->flags & MOD_DPAINT_DRY_LOG) != 0);
+ CLAMP_MIN(pPoint->wetness, 0.0f);
- MEM_freeN(prevPoint);
-}
+ if (pPoint->wetness < surface->color_dry_threshold) {
+ dry_ratio = pPoint->wetness / p_wetness;
-/* Do dissolve and fading effects */
-static void dynamicPaint_surfacePreStep(DynamicPaintSurface *surface, float timescale)
-{
- PaintSurfaceData *sData = surface->data;
- int index;
+ /*
+ * Slowly "shift" paint from wet layer to dry layer as it drys:
+ */
+ /* make sure alpha values are within proper range */
+ CLAMP(pPoint->color[3], 0.0f, 1.0f);
+ CLAMP(pPoint->e_color[3], 0.0f, 1.0f);
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- /* Do drying dissolve effects */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
- /* drying */
- 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;
- value_dissolve(&pPoint->wetness, surface->dry_speed, timescale, (surface->flags & MOD_DPAINT_DRY_LOG));
- if (pPoint->wetness < 0.0f) pPoint->wetness = 0.0f;
-
- if (pPoint->wetness < surface->color_dry_threshold) {
- dry_ratio = pPoint->wetness / p_wetness;
-
- /*
- * Slowly "shift" paint from wet layer to dry layer as it drys:
- */
- /* make sure alpha values are within proper range */
- CLAMP(pPoint->color[3], 0.0f, 1.0f);
- CLAMP(pPoint->e_color[3], 0.0f, 1.0f);
-
- /* get current final blended color of these layers */
- blendColors(pPoint->color, pPoint->color[3], pPoint->e_color, pPoint->e_color[3], f_color);
- /* reduce wet layer alpha by dry factor */
- pPoint->e_color[3] *= dry_ratio;
-
- /* now calculate new alpha for dry layer that keeps final blended color unchanged */
- pPoint->color[3] = (f_color[3] - pPoint->e_color[3]) / (1.0f - pPoint->e_color[3]);
- /* for each rgb component, calculate a new dry layer color that keeps the final blend color
- * with these new alpha values. (wet layer color doesnt change)*/
- if (pPoint->color[3]) {
- for (i = 0; i < 3; i++) {
- pPoint->color[i] = (f_color[i] * f_color[3] - pPoint->e_color[i] * pPoint->e_color[3]) / (pPoint->color[3] * (1.0f - pPoint->e_color[3]));
- }
+ /* get current final blended color of these layers */
+ blendColors(pPoint->color, pPoint->color[3], pPoint->e_color, pPoint->e_color[3], f_color);
+ /* reduce wet layer alpha by dry factor */
+ pPoint->e_color[3] *= dry_ratio;
+
+ /* now calculate new alpha for dry layer that keeps final blended color unchanged */
+ pPoint->color[3] = (f_color[3] - pPoint->e_color[3]) / (1.0f - pPoint->e_color[3]);
+ /* for each rgb component, calculate a new dry layer color that keeps the final blend color
+ * with these new alpha values. (wet layer color doesnt change)*/
+ if (pPoint->color[3]) {
+ for (i = 0; i < 3; i++) {
+ pPoint->color[i] = (f_color[i] * f_color[3] - pPoint->e_color[i] * pPoint->e_color[3]) /
+ (pPoint->color[3] * (1.0f - pPoint->e_color[3]));
}
}
-
- 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->color[3], pPoint->e_color, pPoint->e_color[3], f_color);
- copy_v4_v4(pPoint->color, f_color);
- /* clear wet layer */
- pPoint->wetness = 0.0f;
- pPoint->e_color[3] = 0.0f;
- pPoint->state = DPAINT_PAINT_DRY;
- }
- }
- if (surface->flags & MOD_DPAINT_DISSOLVE) {
- value_dissolve(&pPoint->color[3], surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG));
- CLAMP_MIN(pPoint->color[3], 0.0f);
-
- value_dissolve(&pPoint->e_color[3], surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG));
- CLAMP_MIN(pPoint->e_color[3], 0.0f);
+ 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->color[3], pPoint->e_color, pPoint->e_color[3], f_color);
+ copy_v4_v4(pPoint->color, f_color);
+ /* clear wet layer */
+ pPoint->wetness = 0.0f;
+ pPoint->e_color[3] = 0.0f;
+ pPoint->state = DPAINT_PAINT_DRY;
}
}
- /* dissolve for float types */
- else if (surface->flags & MOD_DPAINT_DISSOLVE &&
- (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
- surface->type == MOD_DPAINT_SURFACE_T_WEIGHT))
- {
- float *point = &((float *)sData->type_data)[index];
- /* log or linear */
- value_dissolve(point, surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG));
- CLAMP_MIN(*point, 0.0f);
+ if (surface->flags & MOD_DPAINT_DISSOLVE) {
+ value_dissolve(&pPoint->color[3], surface->diss_speed, timescale,
+ (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
+ CLAMP_MIN(pPoint->color[3], 0.0f);
+
+ value_dissolve(&pPoint->e_color[3], surface->diss_speed, timescale,
+ (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
+ CLAMP_MIN(pPoint->e_color[3], 0.0f);
}
}
+ /* dissolve for float types */
+ else if (surface->flags & MOD_DPAINT_DISSOLVE &&
+ (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE || surface->type == MOD_DPAINT_SURFACE_T_WEIGHT))
+ {
+ float *point = &((float *)sData->type_data)[index];
+ /* log or linear */
+ value_dissolve(point, surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
+ CLAMP_MIN(*point, 0.0f);
+ }
}
-static int dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *ob)
+static bool dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *ob)
{
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
@@ -4248,67 +4835,159 @@ static int dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *ob
int numOfVerts = dm->getNumVerts(dm);
int i;
- int ret = 0;
- if (!bData->prev_verts) return 1;
+ if (!bData->prev_verts)
+ return true;
/* matrix comparison */
- for (i = 0; i < 4; i++) {
- int j;
- for (j = 0; j < 4; j++)
- if (bData->prev_obmat[i][j] != ob->obmat[i][j]) return 1;
- }
+ if (!equals_m4m4(bData->prev_obmat, ob->obmat))
+ return true;
/* vertices */
-#pragma omp parallel for schedule(static)
for (i = 0; i < numOfVerts; i++) {
- int j;
- for (j = 0; j < 3; j++)
- if (bData->prev_verts[i].co[j] != mvert[i].co[j]) {
- ret = 1;
- break;
- }
+ if (!equals_v3v3(bData->prev_verts[i].co, mvert[i].co)) {
+ return true;
+ }
}
- return ret;
+ return false;
}
-static int surface_needsVelocityData(DynamicPaintSurface *surface, const Scene *scene)
-{
- if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP)
- return 1;
+/* Prepare for surface step by creating PaintBakeNormal data */
+typedef struct DynamicPaintGenerateBakeData {
+ const DynamicPaintSurface *surface;
+ Object *ob;
- if (surface_getBrushFlags(surface, scene) & BRUSH_USES_VELOCITY)
- return 1;
+ const MVert *mvert;
+ const Vec3f *canvas_verts;
- return 0;
-}
+ const bool do_velocity_data;
+ const bool new_bdata;
+} DynamicPaintGenerateBakeData;
-static int surface_needsAccelerationData(DynamicPaintSurface *surface)
+static void dynamic_paint_generate_bake_data_cb(void *userdata, const int index)
{
- if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP)
- return 1;
+ const DynamicPaintGenerateBakeData *data = userdata;
- return 0;
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const PaintAdjData *adj_data = sData->adj_data;
+ const PaintBakeData *bData = sData->bData;
+
+ Object *ob = data->ob;
+
+ const MVert *mvert = data->mvert;
+ const Vec3f *canvas_verts = data->canvas_verts;
+
+ const bool do_velocity_data = data->do_velocity_data;
+ const bool new_bdata = data->new_bdata;
+
+ float prev_point[3] = {0.0f, 0.0f, 0.0f};
+ float temp_nor[3];
+
+ if (do_velocity_data && !new_bdata) {
+ copy_v3_v3(prev_point, bData->realCoord[bData->s_pos[index]].v);
+ }
+
+ /*
+ * Calculate current 3D-position and normal of each surface point
+ */
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
+ float n1[3], n2[3], n3[3];
+ const ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
+ const PaintUVPoint *tPoint = &((PaintUVPoint *)f_data->uv_p)[index];
+
+ bData->s_num[index] = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+ bData->s_pos[index] = index * bData->s_num[index];
+
+ /* per sample coordinates */
+ for (int ss = 0; ss < bData->s_num[index]; ss++) {
+ interp_v3_v3v3v3(bData->realCoord[bData->s_pos[index] + ss].v,
+ canvas_verts[tPoint->v1].v,
+ canvas_verts[tPoint->v2].v,
+ canvas_verts[tPoint->v3].v,
+ f_data->barycentricWeights[index * bData->s_num[index] + ss].v);
+ }
+
+ /* Calculate current pixel surface normal */
+ 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, n1, n2, n3, f_data->barycentricWeights[index * bData->s_num[index]].v);
+ normalize_v3(temp_nor);
+ if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
+ /* Prepare surface normal directional scale to easily convert
+ * brush intersection amount between global and local space */
+ float scaled_nor[3];
+ mul_v3_v3v3(scaled_nor, temp_nor, ob->size);
+ bData->bNormal[index].normal_scale = len_v3(scaled_nor);
+ }
+ mul_mat3_m4_v3(ob->obmat, temp_nor);
+ normalize_v3(temp_nor);
+ negate_v3_v3(bData->bNormal[index].invNorm, temp_nor);
+ }
+ else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+ int ss;
+ if (surface->flags & MOD_DPAINT_ANTIALIAS && adj_data) {
+ bData->s_num[index] = adj_data->n_num[index] + 1;
+ bData->s_pos[index] = adj_data->n_index[index] + index;
+ }
+ else {
+ bData->s_num[index] = 1;
+ bData->s_pos[index] = index;
+ }
+
+ /* calculate position for each sample */
+ for (ss = 0; ss < bData->s_num[index]; ss++) {
+ /* first sample is always point center */
+ copy_v3_v3(bData->realCoord[bData->s_pos[index] + ss].v, canvas_verts[index].v);
+ if (ss > 0) {
+ int t_index = adj_data->n_index[index] + (ss - 1);
+ /* get vertex position at 1/3 of each neigh edge */
+ mul_v3_fl(bData->realCoord[bData->s_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);
+ }
+ }
+
+ /* normal */
+ normal_short_to_float_v3(temp_nor, mvert[index].no);
+ if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
+ /* Prepare surface normal directional scale to easily convert
+ * brush intersection amount between global and local space */
+ float scaled_nor[3];
+ mul_v3_v3v3(scaled_nor, temp_nor, ob->size);
+ bData->bNormal[index].normal_scale = len_v3(scaled_nor);
+ }
+ mul_mat3_m4_v3(ob->obmat, temp_nor);
+ normalize_v3(temp_nor);
+ negate_v3_v3(bData->bNormal[index].invNorm, temp_nor);
+ }
+
+ /* calculate speed vector */
+ if (do_velocity_data && !new_bdata && !bData->clear) {
+ sub_v3_v3v3(bData->velocity[index].v, bData->realCoord[bData->s_pos[index]].v, prev_point);
+ }
}
-/* Prepare for surface step by creating PaintBakeNormal data */
static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Scene *scene, Object *ob)
{
PaintSurfaceData *sData = surface->data;
- PaintAdjData *adj_data = sData->adj_data;
PaintBakeData *bData = sData->bData;
DerivedMesh *dm = surface->canvas->dm;
- int index, new_bdata = 0;
- int do_velocity_data = surface_needsVelocityData(surface, scene);
- int do_accel_data = surface_needsAccelerationData(surface);
+ int index;
+ bool new_bdata = false;
+ const bool do_velocity_data = ((surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) ||
+ (surface_getBrushFlags(surface, scene) & BRUSH_USES_VELOCITY));
+ const bool do_accel_data = (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) != 0;
int canvasNumOfVerts = dm->getNumVerts(dm);
MVert *mvert = dm->getVertArray(dm);
Vec3f *canvas_verts;
if (bData) {
- int surface_moved = dynamicPaint_surfaceHasMoved(surface, ob);
+ const bool surface_moved = dynamicPaint_surfaceHasMoved(surface, ob);
/* get previous speed for accelertaion */
if (do_accel_data && bData->prev_velocity && bData->velocity)
@@ -4324,13 +5003,15 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce
}
canvas_verts = (struct Vec3f *) MEM_mallocN(canvasNumOfVerts * sizeof(struct Vec3f), "Dynamic Paint transformed canvas verts");
- if (!canvas_verts) return 0;
+ if (!canvas_verts)
+ return 0;
/* allocate memory if required */
if (!bData) {
sData->bData = bData = (struct PaintBakeData *) MEM_callocN(sizeof(struct PaintBakeData), "Dynamic Paint bake data");
if (!bData) {
- if (canvas_verts) MEM_freeN(canvas_verts);
+ if (canvas_verts)
+ MEM_freeN(canvas_verts);
return 0;
}
@@ -4343,16 +5024,21 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce
/* if any allocation failed, free everything */
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);
+ if (bData->bNormal)
+ MEM_freeN(bData->bNormal);
+ if (bData->s_pos)
+ MEM_freeN(bData->s_pos);
+ if (bData->s_num)
+ MEM_freeN(bData->s_num);
+ if (bData->realCoord)
+ MEM_freeN(bData->realCoord);
+ if (canvas_verts)
+ MEM_freeN(canvas_verts);
return setError(surface->canvas, N_("Not enough free memory"));
}
- new_bdata = 1;
+ new_bdata = true;
}
if (do_velocity_data && !bData->velocity) {
@@ -4368,7 +5054,7 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce
/*
* Make a transformed copy of canvas derived mesh vertices to avoid recalculation.
*/
- bData->mesh_bounds.valid = 0;
+ bData->mesh_bounds.valid = false;
for (index = 0; index < canvasNumOfVerts; index++) {
copy_v3_v3(canvas_verts[index].v, mvert[index].co);
mul_m4_v3(ob->obmat, canvas_verts[index].v);
@@ -4378,112 +5064,20 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce
/*
* Prepare each surface point for a new step
*/
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- float prev_point[3] = {0.0f, 0.0f, 0.0f};
- if (do_velocity_data && !new_bdata) {
- copy_v3_v3(prev_point, bData->realCoord[bData->s_pos[index]].v);
- }
- /*
- * Calculate current 3D-position and normal of each surface point
- */
- if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
- float n1[3], n2[3], n3[3];
- ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
- PaintUVPoint *tPoint = &((PaintUVPoint *)f_data->uv_p)[index];
- int ss;
-
- bData->s_num[index] = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
- bData->s_pos[index] = index * bData->s_num[index];
-
- /* per sample coordinates */
- for (ss = 0; ss < bData->s_num[index]; ss++) {
- interp_v3_v3v3v3(bData->realCoord[bData->s_pos[index] + ss].v,
- canvas_verts[tPoint->v1].v,
- canvas_verts[tPoint->v2].v,
- canvas_verts[tPoint->v3].v,
- f_data->barycentricWeights[index * bData->s_num[index] + ss].v);
- }
-
- /* Calculate current pixel surface normal */
- normal_short_to_float_v3(n1, mvert[tPoint->v1].no);
- normal_short_to_float_v3(n2, mvert[tPoint->v2].no);
- normal_short_to_float_v3(n3, mvert[tPoint->v3].no);
-
- interp_v3_v3v3v3(bData->bNormal[index].invNorm,
- n1, n2, n3, f_data->barycentricWeights[index * bData->s_num[index]].v);
- mul_mat3_m4_v3(ob->obmat, bData->bNormal[index].invNorm);
- normalize_v3(bData->bNormal[index].invNorm);
- negate_v3(bData->bNormal[index].invNorm);
- }
- else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- int ss;
- if (surface->flags & MOD_DPAINT_ANTIALIAS && adj_data) {
- bData->s_num[index] = adj_data->n_num[index] + 1;
- bData->s_pos[index] = adj_data->n_index[index] + index;
- }
- else {
- bData->s_num[index] = 1;
- bData->s_pos[index] = index;
- }
-
- /* calculate position for each sample */
- for (ss = 0; ss < bData->s_num[index]; ss++) {
- /* first sample is always point center */
- copy_v3_v3(bData->realCoord[bData->s_pos[index] + ss].v, canvas_verts[index].v);
- if (ss > 0) {
- int t_index = adj_data->n_index[index] + (ss - 1);
- /* get vertex position at 1/3 of each neigh edge */
- mul_v3_fl(bData->realCoord[bData->s_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);
- }
- }
-
- /* normal */
- normal_short_to_float_v3(bData->bNormal[index].invNorm, mvert[index].no);
- mul_mat3_m4_v3(ob->obmat, bData->bNormal[index].invNorm);
- normalize_v3(bData->bNormal[index].invNorm);
- negate_v3(bData->bNormal[index].invNorm);
- }
-
- /* Prepare surface normal directional scale to easily convert
- * brush intersection amount between global and local space */
- if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
- surface->type == MOD_DPAINT_SURFACE_T_WAVE)
- {
- float temp_nor[3];
- if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- normal_short_to_float_v3(temp_nor, mvert[index].no);
- normalize_v3(temp_nor);
- }
- else {
- float n1[3], n2[3], n3[3];
- ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
- PaintUVPoint *tPoint = &((PaintUVPoint *)f_data->uv_p)[index];
-
- 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,
- n1, n2, n3, f_data->barycentricWeights[index * bData->s_num[index]].v);
- }
-
- mul_v3_v3(temp_nor, ob->size);
- bData->bNormal[index].normal_scale = len_v3(temp_nor);
- }
-
- /* calculate speed vector */
- if (do_velocity_data && !new_bdata && !bData->clear) {
- sub_v3_v3v3(bData->velocity[index].v, bData->realCoord[bData->s_pos[index]].v, prev_point);
- }
- }
+ DynamicPaintGenerateBakeData data = {
+ .surface = surface, .ob = ob,
+ .mvert = mvert, .canvas_verts = canvas_verts,
+ .do_velocity_data = do_velocity_data, .new_bdata = new_bdata,
+ };
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_generate_bake_data_cb, sData->total_points > 1000);
MEM_freeN(canvas_verts);
/* generate surface space partitioning grid */
surfaceGenerateGrid(surface);
/* calculate current frame adjacency point distances and global dirs */
- dynamicPaint_prepareAdjacencyData(surface, 0);
+ dynamicPaint_prepareAdjacencyData(surface, false);
/* Copy current frame vertices to check against in next frame */
copy_m4_m4(bData->prev_obmat, ob->obmat);
@@ -4503,9 +5097,16 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
PaintBakeData *bData = sData->bData;
DynamicPaintCanvasSettings *canvas = surface->canvas;
int ret = 1;
- if (sData->total_points < 1) return 0;
- dynamicPaint_surfacePreStep(surface, timescale);
+ if (sData->total_points < 1)
+ return 0;
+
+ if (dynamic_paint_surface_needs_dry_dissolve(surface)) {
+ DynamicPaintDissolveDryData data = {.surface = surface, .timescale = timescale};
+ BLI_task_parallel_range(0, sData->total_points, &data,
+ dynamic_paint_surface_pre_step_cb, sData->total_points > 1000);
+ }
+
/*
* Loop through surface's target paint objects and do painting
*/
@@ -4529,24 +5130,23 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
brushObj = NULL;
/* select object */
if (surface->brush_group) {
- if (go->ob) brushObj = go->ob;
+ if (go->ob)
+ brushObj = go->ob;
}
else
brushObj = base->object;
- if (!brushObj) {
- /* skip item */
- if (surface->brush_group) go = go->next;
- else base = base->next;
- continue;
- }
-
/* next item */
if (surface->brush_group)
go = go->next;
else
base = base->next;
+ if (!brushObj) {
+ /* skip item */
+ continue;
+ }
+
/* check if target has an active dp modifier */
md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
@@ -4561,15 +5161,16 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
bData->brush_velocity = MEM_callocN(sData->total_points * sizeof(float) * 4, "Dynamic Paint brush velocity");
/* init adjacency data if not already */
if (!sData->adj_data)
- dynamicPaint_initAdjacencyData(surface, 1);
+ dynamicPaint_initAdjacencyData(surface, true);
if (!bData->bNeighs)
- dynamicPaint_prepareAdjacencyData(surface, 1);
+ dynamicPaint_prepareAdjacencyData(surface, true);
}
/* update object data on this subframe */
if (subframe) {
scene_setSubframe(scene, subframe);
- BKE_object_modifier_update_subframe(scene, brushObj, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ BKE_object_modifier_update_subframe(scene, brushObj, true, SUBFRAME_RECURSION,
+ BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
}
/* Prepare materials if required */
if (brush_usesMaterial(brush, scene))
@@ -4595,7 +5196,8 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
if (subframe) {
scene->r.cfra = scene_frame;
scene->r.subframe = scene_subframe;
- BKE_object_modifier_update_subframe(scene, brushObj, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ BKE_object_modifier_update_subframe(scene, brushObj, true, SUBFRAME_RECURSION,
+ BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
}
/* process special brush effects, like smudge */
@@ -4635,8 +5237,10 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
}
/* Free temporary effect data */
- if (prevPoint) MEM_freeN(prevPoint);
- if (force) MEM_freeN(force);
+ if (prevPoint)
+ MEM_freeN(prevPoint);
+ if (force)
+ MEM_freeN(force);
}
}
@@ -4655,8 +5259,8 @@ int dynamicPaint_calculateFrame(DynamicPaintSurface *surface, Scene *scene, Obje
dynamicPaint_applySurfaceDisplace(surface, surface->canvas->dm);
/* update bake data */
- dynamicPaint_generateBakeData(surface, scene, cObject);
-
+ dynamicPaint_generateBakeData(surface, scene, cObject);
+
/* don't do substeps for first frame */
if (surface->substeps && (frame != surface->start_frame)) {
int st;
@@ -4664,7 +5268,8 @@ int dynamicPaint_calculateFrame(DynamicPaintSurface *surface, Scene *scene, Obje
for (st = 1; st <= surface->substeps; st++) {
float subframe = ((float) st) / (surface->substeps + 1);
- if (!dynamicPaint_doStep(scene, cObject, surface, timescale, subframe)) return 0;
+ if (!dynamicPaint_doStep(scene, cObject, surface, timescale, subframe))
+ return 0;
}
}
diff --git a/source/blender/blenkernel/intern/editmesh_bvh.c b/source/blender/blenkernel/intern/editmesh_bvh.c
index ccea2d4ece4..2927354241c 100644
--- a/source/blender/blenkernel/intern/editmesh_bvh.c
+++ b/source/blender/blenkernel/intern/editmesh_bvh.c
@@ -544,7 +544,7 @@ BVHTreeOverlap *BKE_bmbvh_overlap(const BMBVHTree *bmtree_a, const BMBVHTree *bm
data.tree_pair[0] = bmtree_a;
data.tree_pair[1] = bmtree_b;
- data.epsilon = max_ff(BLI_bvhtree_getepsilon(bmtree_a->tree), BLI_bvhtree_getepsilon(bmtree_b->tree));
+ data.epsilon = max_ff(BLI_bvhtree_get_epsilon(bmtree_a->tree), BLI_bvhtree_get_epsilon(bmtree_b->tree));
return BLI_bvhtree_overlap(bmtree_a->tree, bmtree_b->tree, r_overlap_tot, bmbvh_overlap_cb, &data);
} \ No newline at end of file
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index 66e37203dbb..af5089f742f 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -607,13 +607,15 @@ static void do_texture_effector(EffectorCache *eff, EffectorData *efd, EffectedP
copy_v3_v3(tex_co, point->loc);
- if (eff->pd->flag & PFIELD_TEX_2D) {
- float fac=-dot_v3v3(tex_co, efd->nor);
- madd_v3_v3fl(tex_co, efd->nor, fac);
- }
-
if (eff->pd->flag & PFIELD_TEX_OBJECT) {
mul_m4_v3(eff->ob->imat, tex_co);
+
+ if (eff->pd->flag & PFIELD_TEX_2D)
+ tex_co[2] = 0.0f;
+ }
+ else if (eff->pd->flag & PFIELD_TEX_2D) {
+ float fac=-dot_v3v3(tex_co, efd->nor);
+ madd_v3_v3fl(tex_co, efd->nor, fac);
}
scene_color_manage = BKE_scene_check_color_management_enabled(eff->scene);
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index 485c4f5b29f..f3eb5430bce 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -68,6 +68,7 @@ bool free_gpencil_strokes(bGPDframe *gpf)
/* free stroke memory arrays, then stroke itself */
if (gps->points) MEM_freeN(gps->points);
+ if (gps->triangles) MEM_freeN(gps->triangles);
BLI_freelinkN(&gpf->strokes, gps);
}
@@ -261,6 +262,11 @@ bGPDlayer *gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setactive)
ARRAY_SET_ITEMS(gpl->gcolor_prev, 0.145098f, 0.419608f, 0.137255f); /* green */
ARRAY_SET_ITEMS(gpl->gcolor_next, 0.125490f, 0.082353f, 0.529412f); /* blue */
+ /* high quality fill by default */
+ gpl->flag |= GP_LAYER_HQ_FILL;
+
+ /* default smooth iterations */
+ gpl->draw_smoothlvl = 1;
/* auto-name */
BLI_strncpy(gpl->info, name, sizeof(gpl->info));
@@ -315,7 +321,8 @@ bGPDframe *gpencil_frame_duplicate(bGPDframe *src)
/* make copy of source stroke, then adjust pointer to points too */
gpsd = MEM_dupallocN(gps);
gpsd->points = MEM_dupallocN(gps->points);
-
+ gpsd->triangles = MEM_dupallocN(gps->triangles);
+ gpsd->flag |= GP_STROKE_RECALC_CACHES;
BLI_addtail(&dst->strokes, gpsd);
}
@@ -424,6 +431,7 @@ void gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
/* free the stroke and its data */
MEM_freeN(gps->points);
+ MEM_freeN(gps->triangles);
BLI_freelinkN(&gpf->strokes, gps);
/* if frame has no strokes after this, delete it */
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index d5f9a2dac3e..1ae7ca189fb 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -842,13 +842,6 @@ static ImBuf *add_ibuf_size(unsigned int width, unsigned int height, const char
break;
}
- if (rect_float) {
- /* both byte and float buffers are filling in sRGB space, need to linearize float buffer after BKE_image_buf_fill* functions */
-
- IMB_buffer_float_from_float(rect_float, rect_float, ibuf->channels, IB_PROFILE_LINEAR_RGB, IB_PROFILE_SRGB,
- true, ibuf->x, ibuf->y, ibuf->x, ibuf->x);
- }
-
return ibuf;
}
@@ -1755,6 +1748,7 @@ typedef struct StampData {
char scene[STAMP_NAME_SIZE];
char strip[STAMP_NAME_SIZE];
char rendertime[STAMP_NAME_SIZE];
+ char memory[STAMP_NAME_SIZE];
} StampData;
#undef STAMP_NAME_SIZE
@@ -1876,6 +1870,13 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d
else {
stamp_data->rendertime[0] = '\0';
}
+
+ if (stats && (scene->r.stamp & R_STAMP_MEMORY)) {
+ BLI_snprintf(stamp_data->memory, sizeof(stamp_data->memory), do_prefix ? "Peak Memory %.2fM" : "%.2fM", stats->mem_peak);
+ }
+ else {
+ stamp_data->memory[0] = '\0';
+ }
}
}
@@ -1950,6 +1951,12 @@ static void stampdata_from_template(StampData *stamp_data,
else {
stamp_data->rendertime[0] = '\0';
}
+ if (scene->r.stamp & R_STAMP_MEMORY) {
+ BLI_snprintf(stamp_data->memory, sizeof(stamp_data->memory), "Peak Memory %s", stamp_data_template->memory);
+ }
+ else {
+ stamp_data->memory[0] = '\0';
+ }
}
void BKE_image_stamp_buf(
@@ -2063,6 +2070,21 @@ void BKE_image_stamp_buf(
}
/* Top left corner, below File, Date, Rendertime */
+ if (TEXT_SIZE_CHECK(stamp_data.memory, w, h)) {
+ y -= h;
+
+ /* and space for background. */
+ buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display,
+ 0, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y);
+
+ BLF_position(mono, x, y + y_ofs, 0.0);
+ BLF_draw_buffer(mono, stamp_data.memory, BLF_DRAW_STR_DUMMY_MAX);
+
+ /* the extra pixel for background. */
+ y -= BUFF_MARGIN_Y * 2;
+ }
+
+ /* Top left corner, below File, Date, Memory, Rendertime */
BLF_enable(mono, BLF_WORD_WRAP);
if (TEXT_SIZE_CHECK_WORD_WRAP(stamp_data.note, w, h)) {
y -= h;
@@ -2226,6 +2248,7 @@ void BKE_stamp_info_callback(void *data, struct StampData *stamp_data, StampCall
CALL(scene, "Scene");
CALL(strip, "Strip");
CALL(rendertime, "RenderTime");
+ CALL(memory, "Memory");
#undef CALL
}
diff --git a/source/blender/blenkernel/intern/image_gen.c b/source/blender/blenkernel/intern/image_gen.c
index 10e7d46b315..2c8399adece 100644
--- a/source/blender/blenkernel/intern/image_gen.c
+++ b/source/blender/blenkernel/intern/image_gen.c
@@ -33,30 +33,42 @@
#include "BKE_image.h"
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
#include "BLF_api.h"
-void BKE_image_buf_fill_color(unsigned char *rect, float *rect_float, int width, int height, const float color[4])
+typedef struct FillColorThreadData {
+ unsigned char *rect;
+ float *rect_float;
+ int width;
+ float color[4];
+} FillColorThreadData;
+
+static void image_buf_fill_color_slice(unsigned char *rect,
+ float *rect_float,
+ int width, int height,
+ const float color[4])
{
int x, y;
/* blank image */
if (rect_float) {
+ float linear_color[4];
+ srgb_to_linearrgb_v4(linear_color, color);
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
- copy_v4_v4(rect_float, color);
+ copy_v4_v4(rect_float, linear_color);
rect_float += 4;
}
}
}
-
+
if (rect) {
unsigned char ccol[4];
-
rgba_float_to_uchar(ccol, color);
-
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
-
rect[0] = ccol[0];
rect[1] = ccol[1];
rect[2] = ccol[2];
@@ -67,37 +79,79 @@ void BKE_image_buf_fill_color(unsigned char *rect, float *rect_float, int width,
}
}
+static void image_buf_fill_color_thread_do(void *data_v,
+ int start_scanline,
+ int num_scanlines)
+{
+ FillColorThreadData *data = (FillColorThreadData *)data_v;
+ size_t offset = ((size_t)start_scanline) * data->width * 4;
+ unsigned char *rect = (data->rect != NULL) ? (data->rect + offset) : NULL;
+ float *rect_float = (data->rect_float != NULL) ? (data->rect_float + offset) : NULL;
+ image_buf_fill_color_slice(rect,
+ rect_float,
+ data->width,
+ num_scanlines,
+ data->color);
+}
-void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int width, int height)
+void BKE_image_buf_fill_color(unsigned char *rect,
+ float *rect_float,
+ int width, int height,
+ const float color[4])
{
- /* these two passes could be combined into one, but it's more readable and
+ if (((size_t)width) * height < 64 * 64) {
+ image_buf_fill_color_slice(rect, rect_float, width, height, color);
+ }
+ else {
+ FillColorThreadData data;
+ data.rect = rect;
+ data.rect_float = rect_float;
+ data.width = width;
+ copy_v4_v4(data.color, color);
+ IMB_processor_apply_threaded_scanlines(
+ height, image_buf_fill_color_thread_do, &data);
+ }
+}
+
+static void image_buf_fill_checker_slice(unsigned char *rect,
+ float *rect_float,
+ int width, int height,
+ int offset)
+{
+ /* these two passes could be combined into one, but it's more readable and
* easy to tweak like this, speed isn't really that much of an issue in this situation... */
-
+
int checkerwidth = 32, dark = 1;
int x, y;
unsigned char *rect_orig = rect;
float *rect_float_orig = rect_float;
-
+
float h = 0.0, hoffs = 0.0;
float hsv[3] = {0.0f, 0.9f, 0.9f};
float rgb[3];
+ float dark_linear_color, bright_linear_color;
+ if (rect_float != NULL) {
+ dark_linear_color = srgb_to_linearrgb(0.25f);
+ bright_linear_color = srgb_to_linearrgb(0.58f);
+ }
+
/* checkers */
- for (y = 0; y < height; y++) {
+ for (y = offset; y < height + offset; y++) {
dark = powf(-1.0f, floorf(y / checkerwidth));
-
+
for (x = 0; x < width; x++) {
if (x % checkerwidth == 0) dark = -dark;
-
+
if (rect_float) {
if (dark > 0) {
- rect_float[0] = rect_float[1] = rect_float[2] = 0.25f;
+ rect_float[0] = rect_float[1] = rect_float[2] = dark_linear_color;
rect_float[3] = 1.0f;
}
else {
- rect_float[0] = rect_float[1] = rect_float[2] = 0.58f;
+ rect_float[0] = rect_float[1] = rect_float[2] = bright_linear_color;
rect_float[3] = 1.0f;
}
rect_float += 4;
@@ -120,12 +174,12 @@ void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int widt
rect_float = rect_float_orig;
/* 2nd pass, colored + */
- for (y = 0; y < height; y++) {
+ for (y = offset; y < height + offset; y++) {
hoffs = 0.125f * floorf(y / checkerwidth);
-
+
for (x = 0; x < width; x++) {
h = 0.125f * floorf(x / checkerwidth);
-
+
if ((abs((x % checkerwidth) - (checkerwidth / 2)) < 4) &&
(abs((y % checkerwidth) - (checkerwidth / 2)) < 4))
{
@@ -134,18 +188,16 @@ void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int widt
{
hsv[0] = fmodf(fabsf(h - hoffs), 1.0f);
hsv_to_rgb_v(hsv, rgb);
-
+
if (rect) {
rect[0] = (char)(rgb[0] * 255.0f);
rect[1] = (char)(rgb[1] * 255.0f);
rect[2] = (char)(rgb[2] * 255.0f);
rect[3] = 255;
}
-
+
if (rect_float) {
- rect_float[0] = rgb[0];
- rect_float[1] = rgb[1];
- rect_float[2] = rgb[2];
+ srgb_to_linearrgb_v3_v3(rect_float, rgb);
rect_float[3] = 1.0f;
}
}
@@ -157,13 +209,55 @@ void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int widt
}
}
+typedef struct FillCheckerThreadData {
+ unsigned char *rect;
+ float *rect_float;
+ int width;
+} FillCheckerThreadData;
+
+static void image_buf_fill_checker_thread_do(void *data_v,
+ int start_scanline,
+ int num_scanlines)
+{
+ FillCheckerThreadData *data = (FillCheckerThreadData *)data_v;
+ size_t offset = ((size_t)start_scanline) * data->width * 4;
+ unsigned char *rect = (data->rect != NULL) ? (data->rect + offset) : NULL;
+ float *rect_float = (data->rect_float != NULL) ? (data->rect_float + offset) : NULL;
+ image_buf_fill_checker_slice(rect,
+ rect_float,
+ data->width,
+ num_scanlines,
+ start_scanline);
+}
+
+void BKE_image_buf_fill_checker(unsigned char *rect,
+ float *rect_float,
+ int width, int height)
+{
+ if (((size_t)width) * height < 64 * 64) {
+ image_buf_fill_checker_slice(rect, rect_float, width, height, 0);
+ }
+ else {
+ FillCheckerThreadData data;
+ data.rect = rect;
+ data.rect_float = rect_float;
+ data.width = width;
+ IMB_processor_apply_threaded_scanlines(
+ height, image_buf_fill_checker_thread_do, &data);
+ }
+}
/* Utility functions for BKE_image_buf_fill_checker_color */
#define BLEND_FLOAT(real, add) (real + add <= 1.0f) ? (real + add) : 1.0f
#define BLEND_CHAR(real, add) ((real + (char)(add * 255.0f)) <= 255) ? (real + (char)(add * 255.0f)) : 255
-static void checker_board_color_fill(unsigned char *rect, float *rect_float, int width, int height)
+static void checker_board_color_fill(unsigned char *rect,
+ float *rect_float,
+ int width,
+ int height,
+ int offset,
+ int total_height)
{
int hue_step, y, x;
float hsv[3], rgb[3];
@@ -173,9 +267,9 @@ static void checker_board_color_fill(unsigned char *rect, float *rect_float, int
hue_step = power_of_2_max_i(width / 8);
if (hue_step < 8) hue_step = 8;
- for (y = 0; y < height; y++) {
+ for (y = offset; y < height + offset; y++) {
- hsv[2] = 0.1 + (y * (0.4 / height)); /* use a number lower then 1.0 else its too bright */
+ hsv[2] = 0.1 + (y * (0.4 / total_height)); /* use a number lower then 1.0 else its too bright */
for (x = 0; x < width; x++) {
hsv[0] = (float)((double)(x / hue_step) * 1.0 / width * hue_step);
hsv_to_rgb_v(hsv, rgb);
@@ -185,7 +279,7 @@ static void checker_board_color_fill(unsigned char *rect, float *rect_float, int
rect[1] = (char)(rgb[1] * 255.0f);
rect[2] = (char)(rgb[2] * 255.0f);
rect[3] = 255;
-
+
rect += 4;
}
@@ -194,27 +288,35 @@ static void checker_board_color_fill(unsigned char *rect, float *rect_float, int
rect_float[1] = rgb[1];
rect_float[2] = rgb[2];
rect_float[3] = 1.0f;
-
+
rect_float += 4;
}
}
}
}
-static void checker_board_color_tint(unsigned char *rect, float *rect_float, int width, int height, int size, float blend)
+static void checker_board_color_tint(unsigned char *rect,
+ float *rect_float,
+ int width,
+ int height,
+ int size,
+ float blend,
+ int offset)
{
int x, y;
float blend_half = blend * 0.5f;
- for (y = 0; y < height; y++) {
+ for (y = offset; y < height + offset; y++) {
for (x = 0; x < width; x++) {
- if (((y / size) % 2 == 1 && (x / size) % 2 == 1) || ( (y / size) % 2 == 0 && (x / size) % 2 == 0)) {
+ if (((y / size) % 2 == 1 && (x / size) % 2 == 1) ||
+ ((y / size) % 2 == 0 && (x / size) % 2 == 0))
+ {
if (rect) {
rect[0] = (char)BLEND_CHAR(rect[0], blend);
rect[1] = (char)BLEND_CHAR(rect[1], blend);
rect[2] = (char)BLEND_CHAR(rect[2], blend);
rect[3] = 255;
-
+
rect += 4;
}
if (rect_float) {
@@ -222,7 +324,7 @@ static void checker_board_color_tint(unsigned char *rect, float *rect_float, int
rect_float[1] = BLEND_FLOAT(rect_float[1], blend);
rect_float[2] = BLEND_FLOAT(rect_float[2], blend);
rect_float[3] = 1.0f;
-
+
rect_float += 4;
}
}
@@ -232,7 +334,7 @@ static void checker_board_color_tint(unsigned char *rect, float *rect_float, int
rect[1] = (char)BLEND_CHAR(rect[1], blend_half);
rect[2] = (char)BLEND_CHAR(rect[2], blend_half);
rect[3] = 255;
-
+
rect += 4;
}
if (rect_float) {
@@ -240,19 +342,24 @@ static void checker_board_color_tint(unsigned char *rect, float *rect_float, int
rect_float[1] = BLEND_FLOAT(rect_float[1], blend_half);
rect_float[2] = BLEND_FLOAT(rect_float[2], blend_half);
rect_float[3] = 1.0f;
-
+
rect_float += 4;
}
}
-
+
}
}
}
-static void checker_board_grid_fill(unsigned char *rect, float *rect_float, int width, int height, float blend)
+static void checker_board_grid_fill(unsigned char *rect,
+ float *rect_float,
+ int width,
+ int height,
+ float blend,
+ int offset)
{
int x, y;
- for (y = 0; y < height; y++) {
+ for (y = offset; y < height + offset; y++) {
for (x = 0; x < width; x++) {
if (((y % 32) == 0) || ((x % 32) == 0) || x == 0) {
if (rect) {
@@ -268,7 +375,7 @@ static void checker_board_grid_fill(unsigned char *rect, float *rect_float, int
rect_float[1] = BLEND_FLOAT(rect_float[1], blend);
rect_float[2] = BLEND_FLOAT(rect_float[2], blend);
rect_float[3] = 1.0f;
-
+
rect_float += 4;
}
}
@@ -282,7 +389,12 @@ static void checker_board_grid_fill(unsigned char *rect, float *rect_float, int
/* defined in image.c */
-static void checker_board_text(unsigned char *rect, float *rect_float, int width, int height, int step, int outline)
+static void checker_board_text(unsigned char *rect,
+ float *rect_float,
+ int width,
+ int height,
+ int step,
+ int outline)
{
int x, y;
int pen_x, pen_y;
@@ -342,14 +454,71 @@ static void checker_board_text(unsigned char *rect, float *rect_float, int width
BLF_buffer(mono, NULL, NULL, 0, 0, 0, NULL);
}
+static void checker_board_color_prepare_slice(unsigned char *rect,
+ float *rect_float,
+ int width,
+ int height,
+ int offset,
+ int total_height)
+{
+ checker_board_color_fill(rect, rect_float, width, height, offset, total_height);
+ checker_board_color_tint(rect, rect_float, width, height, 1, 0.03f, offset);
+ checker_board_color_tint(rect, rect_float, width, height, 4, 0.05f, offset);
+ checker_board_color_tint(rect, rect_float, width, height, 32, 0.07f, offset);
+ checker_board_color_tint(rect, rect_float, width, height, 128, 0.15f, offset);
+ checker_board_grid_fill(rect, rect_float, width, height, 1.0f / 4.0f, offset);
+}
+
+typedef struct FillCheckerColorThreadData {
+ unsigned char *rect;
+ float *rect_float;
+ int width, height;
+} FillCheckerColorThreadData;
+
+static void checker_board_color_prepare_thread_do(void *data_v,
+ int start_scanline,
+ int num_scanlines)
+{
+ FillCheckerColorThreadData *data = (FillCheckerColorThreadData *)data_v;
+ size_t offset = ((size_t)data->width) * start_scanline * 4;
+ unsigned char *rect = (data->rect != NULL) ? (data->rect + offset) : NULL;
+ float *rect_float = (data->rect_float != NULL) ? (data->rect_float + offset) : NULL;
+ checker_board_color_prepare_slice(rect,
+ rect_float,
+ data->width,
+ num_scanlines,
+ start_scanline,
+ data->height);
+}
+
void BKE_image_buf_fill_checker_color(unsigned char *rect, float *rect_float, int width, int height)
{
- checker_board_color_fill(rect, rect_float, width, height);
- checker_board_color_tint(rect, rect_float, width, height, 1, 0.03f);
- checker_board_color_tint(rect, rect_float, width, height, 4, 0.05f);
- checker_board_color_tint(rect, rect_float, width, height, 32, 0.07f);
- checker_board_color_tint(rect, rect_float, width, height, 128, 0.15f);
- checker_board_grid_fill(rect, rect_float, width, height, 1.0f / 4.0f);
+ if (((size_t)width) * height < 64 * 64) {
+ checker_board_color_prepare_slice(rect, rect_float, width, height, 0, height);
+ }
+ else {
+ FillCheckerColorThreadData data;
+ data.rect = rect;
+ data.rect_float = rect_float;
+ data.width = width;
+ data.height = height;
+ IMB_processor_apply_threaded_scanlines(
+ height, checker_board_color_prepare_thread_do, &data);
+ }
checker_board_text(rect, rect_float, width, height, 128, 2);
+
+ if (rect_float != NULL) {
+ /* TODO(sergey): Currently it's easier to fill in form buffer and
+ * linearize it afterwards. This could be optimized with some smart
+ * trickery around blending factors and such.
+ */
+ IMB_buffer_float_from_float_threaded(rect_float, rect_float,
+ 4,
+ IB_PROFILE_LINEAR_RGB,
+ IB_PROFILE_SRGB,
+ true,
+ width, height,
+ width, width);
+ }
}
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index 57c02ec6329..b350e932281 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -1082,6 +1082,7 @@ void BKE_lattice_modifiers_calc(Scene *scene, Object *ob)
md->scene = scene;
+ if (!(mti->flags & eModifierTypeFlag_AcceptsLattice)) continue;
if (!(md->mode & eModifierMode_Realtime)) continue;
if (editmode && !(md->mode & eModifierMode_Editmode)) continue;
if (mti->isDisabled && mti->isDisabled(md, 0)) continue;
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 071071d9d0f..64c9ddb5b38 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -1764,7 +1764,7 @@ void BKE_main_id_clear_newpoins(Main *bmain)
}
}
-static void lib_indirect_test_id(ID *id, Library *lib)
+static void lib_indirect_test_id(ID *id, const Library *lib)
{
#define LIBTAG(a) \
if (a && a->id.lib) { a->id.tag &= ~LIB_TAG_INDIRECT; a->id.tag |= LIB_TAG_EXTERN; } (void)0
@@ -1811,9 +1811,14 @@ static void lib_indirect_test_id(ID *id, Library *lib)
#undef LIBTAG
}
-/* if lib!=NULL, only all from lib local
- * bmain is almost certainly G.main */
-void BKE_library_make_local(Main *bmain, Library *lib, bool untagged_only, bool set_fake)
+/** Make linked datablocks local.
+ *
+ * \param bmain Almost certainly G.main.
+ * \param lib If not NULL, only make local datablocks from this library.
+ * \param untagged_only If true, only make local datablocks not tagged with LIB_TAG_PRE_EXISTING.
+ * \param set_fake If true, set fake user on all localized datablocks (except group and objects ones).
+ */
+void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged_only, const bool set_fake)
{
ListBase *lbarray[MAX_LIBARRAY];
ID *id, *idn;
diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c
index c8bb2e0e758..a472b6e5bc1 100644
--- a/source/blender/blenkernel/intern/mesh_mapping.c
+++ b/source/blender/blenkernel/intern/mesh_mapping.c
@@ -262,6 +262,51 @@ void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map, int **r_mem,
}
/**
+ * Generates a map where the key is the edge and the value is a list of looptris that use that edge.
+ * The lists are allocated from one memory pool.
+ */
+void BKE_mesh_vert_looptri_map_create(
+ MeshElemMap **r_map, int **r_mem,
+ const MVert *UNUSED(mvert), const int totvert,
+ const MLoopTri *mlooptri, const int totlooptri,
+ const MLoop *mloop, const int UNUSED(totloop))
+{
+ MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, __func__);
+ int *indices = MEM_mallocN(sizeof(int) * (size_t)totlooptri * 3, __func__);
+ int *index_step;
+ const MLoopTri *mlt;
+ int i;
+
+ /* count face users */
+ for (i = 0, mlt = mlooptri; i < totlooptri; mlt++, i++) {
+ for (int j = 3; j--;) {
+ map[mloop[mlt->tri[j]].v].count++;
+ }
+ }
+
+ /* create offsets */
+ index_step = indices;
+ for (i = 0; i < totvert; i++) {
+ map[i].indices = index_step;
+ index_step += map[i].count;
+
+ /* re-count, using this as an index below */
+ map[i].count = 0;
+ }
+
+ /* assign looptri-edge users */
+ for (i = 0, mlt = mlooptri; i < totlooptri; mlt++, i++) {
+ for (int j = 3; j--;) {
+ MeshElemMap *map_ele = &map[mloop[mlt->tri[j]].v];
+ map_ele->indices[map_ele->count++] = i;
+ }
+ }
+
+ *r_map = map;
+ *r_mem = indices;
+}
+
+/**
* Generates a map where the key is the vertex and the value is a list of edges that use that vertex as an endpoint.
* The lists are allocated from one memory pool.
*/
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index 49dd0b104ab..ba890b005d8 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -284,7 +284,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
bool fix_normal = true;
for (j = 0; j < 3; j++) {
- if (!finite(mv->co[j])) {
+ if (!isfinite(mv->co[j])) {
PRINT_ERR("\tVertex %u: has invalid coordinate\n", i);
if (do_fixes) {
@@ -765,7 +765,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
for (j = 0, dw = dv->dw; j < dv->totweight; j++, dw++) {
/* note, greater than max defgroups is accounted for in our code, but not < 0 */
- if (!finite(dw->weight)) {
+ if (!isfinite(dw->weight)) {
PRINT_ERR("\tVertex deform %u, group %d has weight: %f\n", i, dw->def_nr, dw->weight);
if (do_fixes) {
dw->weight = 0.0f;
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index a3597541529..51bc0b597c7 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -232,6 +232,11 @@ bool BKE_object_support_modifier_type_check(Object *ob, int modifier_type)
mti = modifierType_getInfo(modifier_type);
+
+ if (ob->type == OB_LATTICE && (mti->flags & eModifierTypeFlag_AcceptsLattice) == 0) {
+ return false;
+ }
+
if (!((mti->flags & eModifierTypeFlag_AcceptsCVs) ||
(ob->type == OB_MESH && (mti->flags & eModifierTypeFlag_AcceptsMesh))))
{
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 330b5922c9a..d73f087a3fe 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -979,16 +979,7 @@ static void pbvh_update_normals_accum_task_cb(void *userdata, const int n)
* Not exact equivalent though, since atomicity is only ensured for one component
* of the vector at a time, but here it shall not make any sensible difference. */
for (int k = 3; k--; ) {
- /* Atomic float addition.
- * Note that since collision are unlikely, loop will nearly always run once. */
- float oldval, newval;
- uint32_t prevval;
- do {
- oldval = vnors[v][k];
- newval = oldval + fn[k];
- prevval = atomic_cas_uint32(
- (uint32_t *)&vnors[v][k], *(uint32_t *)(&oldval), *(uint32_t *)(&newval));
- } while (UNLIKELY(prevval != *(uint32_t *)(&oldval)));
+ atomic_add_fl(&vnors[v][k], fn[k]);
}
}
}
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 1a452fbdc96..e06c7a43dd8 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -101,11 +101,6 @@
#include "bmesh.h"
-#ifdef WIN32
-#else
-# include <sys/time.h>
-#endif
-
const char *RE_engine_id_BLENDER_RENDER = "BLENDER_RENDER";
const char *RE_engine_id_BLENDER_GAME = "BLENDER_GAME";
const char *RE_engine_id_CYCLES = "CYCLES";
@@ -547,7 +542,7 @@ void BKE_scene_init(Scene *sce)
sce->r.bake.im_format.compress = 15;
sce->r.scemode = R_DOCOMP | R_DOSEQ | R_EXTENSION;
- sce->r.stamp = R_STAMP_TIME | R_STAMP_FRAME | R_STAMP_DATE | R_STAMP_CAMERA | R_STAMP_SCENE | R_STAMP_FILENAME | R_STAMP_RENDERTIME;
+ sce->r.stamp = R_STAMP_TIME | R_STAMP_FRAME | R_STAMP_DATE | R_STAMP_CAMERA | R_STAMP_SCENE | R_STAMP_FILENAME | R_STAMP_RENDERTIME | R_STAMP_MEMORY;
sce->r.stamp_font_id = 12;
sce->r.fg_stamp[0] = sce->r.fg_stamp[1] = sce->r.fg_stamp[2] = 0.8f;
sce->r.fg_stamp[3] = 1.0f;
@@ -2409,7 +2404,6 @@ SceneRenderView *BKE_scene_multiview_render_view_findindex(const RenderData *rd,
if ((rd->scemode & R_MULTIVIEW) == 0)
return NULL;
- nr = 0;
for (srv = rd->views.first, nr = 0; srv; srv = srv->next) {
if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
if (nr++ == view_id)
@@ -2440,7 +2434,6 @@ int BKE_scene_multiview_view_id_get(const RenderData *rd, const char *viewname)
if ((!viewname) || (!viewname[0]))
return 0;
- nr = 0;
for (srv = rd->views.first, nr = 0; srv; srv = srv->next) {
if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
if (STREQ(viewname, srv->name)) {
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index 4086fc2b0f3..3de4a426973 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -3060,7 +3060,7 @@ static ImBuf *do_gaussian_blur_effect(const SeqRenderData *context,
ibuf1 = out;
init_data.ibuf = ibuf1;
- out = prepare_effect_imbufs(context, ibuf1, NULL, NULL);;
+ out = prepare_effect_imbufs(context, ibuf1, NULL, NULL);
init_data.out = out;
IMB_processor_apply_threaded(out->y,
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index badf78edfb1..e855f6faa22 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -245,11 +245,11 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
* for finding the best hit, to get the real dist,
* measure the len_v3v3() from the input coord to hit.co */
BVHTreeRayHit hit;
- BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
+ void *treeData = NULL;
/* auxiliary target */
DerivedMesh *auxMesh = NULL;
- BVHTreeFromMesh auxData = NULL_BVHTreeFromMesh;
+ void *auxData = NULL;
SpaceTransform local2aux;
/* If the user doesn't allows to project in any direction of projection axis
@@ -285,19 +285,44 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
}
/* use editmesh to avoid array allocation */
+ BMEditMesh *emtarget = NULL, *emaux = NULL;
+ BVHTreeFromEditMesh emtreedata_stack, emauxdata_stack;
+ BVHTreeFromMesh dmtreedata_stack, dmauxdata_stack;
+ BVHTree *targ_tree;
+ void *targ_callback;
if (calc->smd->target && calc->target->type == DM_TYPE_EDITBMESH) {
- treeData.em_evil = BKE_editmesh_from_object(calc->smd->target);
- treeData.em_evil_all = true;
+ emtarget = BKE_editmesh_from_object(calc->smd->target);
+ if ((targ_tree = bvhtree_from_editmesh_looptri(&emtreedata_stack, emtarget, 0.0, 4, 6))) {
+ targ_callback = emtreedata_stack.raycast_callback;
+ treeData = &emtreedata_stack;
+ }
}
- if (calc->smd->auxTarget && auxMesh->type == DM_TYPE_EDITBMESH) {
- auxData.em_evil = BKE_editmesh_from_object(calc->smd->auxTarget);
- auxData.em_evil_all = true;
+ else {
+ if ((targ_tree = bvhtree_from_mesh_looptri(&dmtreedata_stack, calc->target, 0.0, 4, 6))) {
+ targ_callback = dmtreedata_stack.raycast_callback;
+ treeData = &dmtreedata_stack;
+ }
}
-
- /* After sucessufuly build the trees, start projection vertexs */
- if (bvhtree_from_mesh_looptri(&treeData, calc->target, 0.0, 4, 6) &&
- (auxMesh == NULL || bvhtree_from_mesh_looptri(&auxData, auxMesh, 0.0, 4, 6)))
- {
+ if (targ_tree) {
+ BVHTree *aux_tree = NULL;
+ void *aux_callback;
+ if (auxMesh != NULL) {
+ /* use editmesh to avoid array allocation */
+ if (calc->smd->auxTarget && auxMesh->type == DM_TYPE_EDITBMESH) {
+ emaux = BKE_editmesh_from_object(calc->smd->auxTarget);
+ if ((aux_tree = bvhtree_from_editmesh_looptri(&emauxdata_stack, emaux, 0.0, 4, 6)) != NULL) {
+ aux_callback = emauxdata_stack.raycast_callback;
+ auxData = &emauxdata_stack;
+ }
+ }
+ else {
+ if ((aux_tree = bvhtree_from_mesh_looptri(&dmauxdata_stack, calc->target, 0.0, 4, 6)) != NULL) {
+ aux_callback = dmauxdata_stack.raycast_callback;
+ auxData = &dmauxdata_stack;
+ }
+ }
+ }
+ /* After sucessufuly build the trees, start projection vertexs */
#ifndef __APPLE__
#pragma omp parallel for private(i, hit) schedule(static) if (calc->numVerts > BKE_MESH_OMP_LIMIT)
@@ -340,15 +365,17 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
/* Project over positive direction of axis */
if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) {
- if (auxData.tree) {
- BKE_shrinkwrap_project_normal(0, tmp_co, tmp_no,
- &local2aux, auxData.tree, &hit,
- auxData.raycast_callback, &auxData);
+ if (aux_tree) {
+ BKE_shrinkwrap_project_normal(
+ 0, tmp_co, tmp_no,
+ &local2aux, aux_tree, &hit,
+ aux_callback, auxData);
}
- BKE_shrinkwrap_project_normal(calc->smd->shrinkOpts, tmp_co, tmp_no,
- &calc->local2target, treeData.tree, &hit,
- treeData.raycast_callback, &treeData);
+ BKE_shrinkwrap_project_normal(
+ calc->smd->shrinkOpts, tmp_co, tmp_no,
+ &calc->local2target, targ_tree, &hit,
+ targ_callback, treeData);
}
/* Project over negative direction of axis */
@@ -356,15 +383,17 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
float inv_no[3];
negate_v3_v3(inv_no, tmp_no);
- if (auxData.tree) {
- BKE_shrinkwrap_project_normal(0, tmp_co, inv_no,
- &local2aux, auxData.tree, &hit,
- auxData.raycast_callback, &auxData);
+ if (aux_tree) {
+ BKE_shrinkwrap_project_normal(
+ 0, tmp_co, inv_no,
+ &local2aux, aux_tree, &hit,
+ aux_callback, auxData);
}
- BKE_shrinkwrap_project_normal(calc->smd->shrinkOpts, tmp_co, inv_no,
- &calc->local2target, treeData.tree, &hit,
- treeData.raycast_callback, &treeData);
+ BKE_shrinkwrap_project_normal(
+ calc->smd->shrinkOpts, tmp_co, inv_no,
+ &calc->local2target, targ_tree, &hit,
+ targ_callback, treeData);
}
/* don't set the initial dist (which is more efficient),
@@ -383,8 +412,14 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
}
/* free data structures */
- free_bvhtree_from_mesh(&treeData);
- free_bvhtree_from_mesh(&auxData);
+ if (treeData) {
+ if (emtarget) free_bvhtree_from_editmesh(treeData);
+ else free_bvhtree_from_mesh(treeData);
+ }
+ if (auxData) {
+ if (emaux) free_bvhtree_from_editmesh(auxData);
+ else free_bvhtree_from_mesh(auxData);
+ }
}
/*
diff --git a/source/blender/blenkernel/intern/sketch.c b/source/blender/blenkernel/intern/sketch.c
index 0d355abb49b..6f5c264f658 100644
--- a/source/blender/blenkernel/intern/sketch.c
+++ b/source/blender/blenkernel/intern/sketch.c
@@ -50,8 +50,6 @@ void freeSketch(SK_Sketch *sketch)
sk_freeStroke(stk);
}
- BLI_freelistN(&sketch->depth_peels);
-
MEM_freeN(sketch);
}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index a8e8f10962d..5b6adb3778a 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -3369,13 +3369,14 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
CCGSubSurf *ss = ccgdm->ss;
CCGKey key;
int colType;
- const MLoopCol *mloopcol;
+ const MLoopCol *mloopcol = NULL;
MTexPoly *mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY);
DMFlagMat *faceFlags = ccgdm->faceFlags;
DMDrawOption draw_option;
int i, totpoly;
bool flush;
- bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0;
+ const bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0;
+ const bool use_colors = (flag & DM_DRAW_USE_COLORS) != 0;
unsigned int next_actualFace;
unsigned int gridFaces = ccgSubSurf_getGridSize(ss) - 1;
int mat_index;
@@ -3394,15 +3395,17 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
CCG_key_top_level(&key, ss);
ccgdm_pbvh_update(ccgdm);
- colType = CD_TEXTURE_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- if (!mloopcol) {
- colType = CD_PREVIEW_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- }
- if (!mloopcol) {
- colType = CD_MLOOPCOL;
+ if (use_colors) {
+ colType = CD_TEXTURE_MLOOPCOL;
mloopcol = dm->getLoopDataArray(dm, colType);
+ if (!mloopcol) {
+ colType = CD_PREVIEW_MLOOPCOL;
+ mloopcol = dm->getLoopDataArray(dm, colType);
+ }
+ if (!mloopcol) {
+ colType = CD_MLOOPCOL;
+ mloopcol = dm->getLoopDataArray(dm, colType);
+ }
}
GPU_vertex_setup(dm);
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index cf11fe2323d..c0a373395dc 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -102,7 +102,7 @@ typedef struct bUnitDef {
/* define a single unit */
typedef struct bUnitCollection {
- struct bUnitDef *units;
+ const struct bUnitDef *units;
int base_unit; /* basic unit index (when user doesn't specify unit explicitly) */
int flag; /* options for this system */
int length; /* to quickly find the last item */
@@ -113,7 +113,7 @@ static struct bUnitDef buDummyDef[] = { {"", NULL, "", NULL, NULL, 1.0, 0.0}, {N
static struct bUnitCollection buDummyCollection = {buDummyDef, 0, 0, sizeof(buDummyDef)};
/* Lengths */
-static struct bUnitDef buMetricLenDef[] = {
+static const struct bUnitDef buMetricLenDef[] = {
{"kilometer", "kilometers", "km", NULL, "Kilometers", UN_SC_KM, 0.0, B_UNIT_DEF_NONE},
{"hectometer", "hectometers", "hm", NULL, "100 Meters", UN_SC_HM, 0.0, B_UNIT_DEF_SUPPRESS},
{"dekameter", "dekameters", "dam", NULL, "10 Meters", UN_SC_DAM, 0.0, B_UNIT_DEF_SUPPRESS},
@@ -131,7 +131,7 @@ static struct bUnitDef buMetricLenDef[] = {
#endif
{NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
};
-static struct bUnitCollection buMetricLenCollection = {buMetricLenDef, 3, 0, sizeof(buMetricLenDef) / sizeof(bUnitDef)};
+static const struct bUnitCollection buMetricLenCollection = {buMetricLenDef, 3, 0, sizeof(buMetricLenDef) / sizeof(bUnitDef)};
static struct bUnitDef buImperialLenDef[] = {
{"mile", "miles", "mi", "m", "Miles", UN_SC_MI, 0.0, B_UNIT_DEF_NONE},
@@ -289,7 +289,7 @@ static struct bUnitCollection buCameraLenCollection = {buCameraLenDef, 3, 0, siz
#define UNIT_SYSTEM_TOT (((sizeof(bUnitSystems) / B_UNIT_TYPE_TOT) / sizeof(void *)) - 1)
-static struct bUnitCollection *bUnitSystems[][B_UNIT_TYPE_TOT] = {
+static const struct bUnitCollection *bUnitSystems[][B_UNIT_TYPE_TOT] = {
{NULL, NULL, NULL, NULL, NULL, &buNaturalRotCollection, &buNaturalTimeCollection, NULL, NULL, NULL},
{NULL, &buMetricLenCollection, &buMetricAreaCollection, &buMetricVolCollection, &buMetricMassCollection, &buNaturalRotCollection, &buNaturalTimeCollection, &buMetricVelCollection, &buMetricAclCollection, &buCameraLenCollection}, /* metric */
{NULL, &buImperialLenCollection, &buImperialAreaCollection, &buImperialVolCollection, &buImperialMassCollection, &buNaturalRotCollection, &buNaturalTimeCollection, &buImperialVelCollection, &buImperialAclCollection, &buCameraLenCollection}, /* imperial */
@@ -299,20 +299,21 @@ static struct bUnitCollection *bUnitSystems[][B_UNIT_TYPE_TOT] = {
/* internal, has some option not exposed */
-static bUnitCollection *unit_get_system(int system, int type)
+static const bUnitCollection *unit_get_system(int system, int type)
{
assert((system > -1) && (system < UNIT_SYSTEM_TOT) && (type > -1) && (type < B_UNIT_TYPE_TOT));
return bUnitSystems[system][type]; /* select system to use, metric/imperial/other? */
}
-static bUnitDef *unit_default(bUnitCollection *usys)
+static const bUnitDef *unit_default(const bUnitCollection *usys)
{
return &usys->units[usys->base_unit];
}
-static bUnitDef *unit_best_fit(double value, bUnitCollection *usys, bUnitDef *unit_start, int suppress)
+static const bUnitDef *unit_best_fit(
+ double value, const bUnitCollection *usys, const bUnitDef *unit_start, int suppress)
{
- bUnitDef *unit;
+ const bUnitDef *unit;
double value_abs = value > 0.0 ? value : -value;
for (unit = unit_start ? unit_start : usys->units; unit->name; unit++) {
@@ -337,19 +338,21 @@ static bUnitDef *unit_best_fit(double value, bUnitCollection *usys, bUnitDef *un
}
/* convert into 2 units and 2 values for "2ft, 3inch" syntax */
-static void unit_dual_convert(double value, bUnitCollection *usys, bUnitDef **unit_a, bUnitDef **unit_b,
- double *value_a, double *value_b)
+static void unit_dual_convert(
+ double value, const bUnitCollection *usys,
+ bUnitDef const **r_unit_a, bUnitDef const **r_unit_b,
+ double *r_value_a, double *r_value_b)
{
- bUnitDef *unit = unit_best_fit(value, usys, NULL, 1);
+ const bUnitDef *unit = unit_best_fit(value, usys, NULL, 1);
- *value_a = (value < 0.0 ? ceil : floor)(value / unit->scalar) * unit->scalar;
- *value_b = value - (*value_a);
+ *r_value_a = (value < 0.0 ? ceil : floor)(value / unit->scalar) * unit->scalar;
+ *r_value_b = value - (*r_value_a);
- *unit_a = unit;
- *unit_b = unit_best_fit(*value_b, usys, *unit_a, 1);
+ *r_unit_a = unit;
+ *r_unit_b = unit_best_fit(*r_value_b, usys, *r_unit_a, 1);
}
-static size_t unit_as_string(char *str, int len_max, double value, int prec, bUnitCollection *usys,
+static size_t unit_as_string(char *str, int len_max, double value, int prec, const bUnitCollection *usys,
/* non exposed options */
const bUnitDef *unit, char pad)
{
@@ -422,14 +425,14 @@ static size_t unit_as_string(char *str, int len_max, double value, int prec, bUn
*/
size_t bUnit_AsString(char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad)
{
- bUnitCollection *usys = unit_get_system(system, type);
+ const bUnitCollection *usys = unit_get_system(system, type);
if (usys == NULL || usys->units[0].name == NULL)
usys = &buDummyCollection;
/* split output makes sense only for length, mass and time */
if (split && (type == B_UNIT_LENGTH || type == B_UNIT_MASS || type == B_UNIT_TIME || type == B_UNIT_CAMERA)) {
- bUnitDef *unit_a, *unit_b;
+ const bUnitDef *unit_a, *unit_b;
double value_a, value_b;
unit_dual_convert(value, usys, &unit_a, &unit_b, &value_a, &value_b);
@@ -522,7 +525,7 @@ static bool ch_is_op(char op)
}
}
-static int unit_scale_str(char *str, int len_max, char *str_tmp, double scale_pref, bUnitDef *unit,
+static int unit_scale_str(char *str, int len_max, char *str_tmp, double scale_pref, const bUnitDef *unit,
const char *replace_str)
{
char *str_found;
@@ -571,7 +574,7 @@ static int unit_scale_str(char *str, int len_max, char *str_tmp, double scale_pr
return 0;
}
-static int unit_replace(char *str, int len_max, char *str_tmp, double scale_pref, bUnitDef *unit)
+static int unit_replace(char *str, int len_max, char *str_tmp, double scale_pref, const bUnitDef *unit)
{
int ofs = 0;
ofs += unit_scale_str(str + ofs, len_max - ofs, str_tmp, scale_pref, unit, unit->name_short);
@@ -581,7 +584,7 @@ static int unit_replace(char *str, int len_max, char *str_tmp, double scale_pref
return ofs;
}
-static bool unit_find(const char *str, bUnitDef *unit)
+static bool unit_find(const char *str, const bUnitDef *unit)
{
if (unit_find_str(str, unit->name_short)) return true;
if (unit_find_str(str, unit->name_plural)) return true;
@@ -591,12 +594,12 @@ static bool unit_find(const char *str, bUnitDef *unit)
return false;
}
-static bUnitDef *unit_detect_from_str(bUnitCollection *usys, const char *str, const char *str_prev)
+static const bUnitDef *unit_detect_from_str(const bUnitCollection *usys, const char *str, const char *str_prev)
{
/* Try to find a default unit from current or previous string.
* This allows us to handle cases like 2 + 2mm, people would expect to get 4mm, not 2.002m!
* Note this does not handle corner cases like 2 + 2cm + 1 + 2.5mm... We can't support everything. */
- bUnitDef *unit = NULL;
+ const bUnitDef *unit = NULL;
/* see which units the new value has */
for (unit = usys->units; unit->name; unit++) {
@@ -636,9 +639,9 @@ static bUnitDef *unit_detect_from_str(bUnitCollection *usys, const char *str, co
*/
bool bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double scale_pref, int system, int type)
{
- bUnitCollection *usys = unit_get_system(system, type);
+ const bUnitCollection *usys = unit_get_system(system, type);
- bUnitDef *unit = NULL, *default_unit;
+ const bUnitDef *unit = NULL, *default_unit;
double scale_pref_base = scale_pref;
char str_tmp[TEMP_STR_SIZE];
bool changed = false;
@@ -679,7 +682,7 @@ bool bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double sc
* In other words, when in metrics, typing '2+2in' will give 2 meters 2 inches, not 4 inches.
* I do think this is the desired behavior!
*/
- bUnitCollection *usys_iter;
+ const bUnitCollection *usys_iter;
int system_iter;
for (system_iter = 0; system_iter < UNIT_SYSTEM_TOT; system_iter++) {
@@ -730,9 +733,9 @@ bool bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double sc
/* 45µm --> 45um */
void bUnit_ToUnitAltName(char *str, int len_max, const char *orig_str, int system, int type)
{
- bUnitCollection *usys = unit_get_system(system, type);
+ const bUnitCollection *usys = unit_get_system(system, type);
- bUnitDef *unit;
+ const bUnitDef *unit;
/* find and substitute all units */
for (unit = usys->units; unit->name; unit++) {
@@ -769,8 +772,8 @@ void bUnit_ToUnitAltName(char *str, int len_max, const char *orig_str, int syste
double bUnit_ClosestScalar(double value, int system, int type)
{
- bUnitCollection *usys = unit_get_system(system, type);
- bUnitDef *unit;
+ const bUnitCollection *usys = unit_get_system(system, type);
+ const bUnitDef *unit;
if (usys == NULL)
return -1;
@@ -784,7 +787,7 @@ double bUnit_ClosestScalar(double value, int system, int type)
double bUnit_BaseScalar(int system, int type)
{
- bUnitCollection *usys = unit_get_system(system, type);
+ const bUnitCollection *usys = unit_get_system(system, type);
return unit_default(usys)->scalar;
}
@@ -794,34 +797,34 @@ bool bUnit_IsValid(int system, int type)
return !(system < 0 || system > UNIT_SYSTEM_TOT || type < 0 || type > B_UNIT_TYPE_TOT);
}
-void bUnit_GetSystem(void **usys_pt, int *len, int system, int type)
+void bUnit_GetSystem(int system, int type, void const **r_usys_pt, int *r_len)
{
- bUnitCollection *usys = unit_get_system(system, type);
- *usys_pt = usys;
+ const bUnitCollection *usys = unit_get_system(system, type);
+ *r_usys_pt = usys;
if (usys == NULL) {
- *len = 0;
+ *r_len = 0;
return;
}
- *len = usys->length;
+ *r_len = usys->length;
}
-int bUnit_GetBaseUnit(void *usys_pt)
+int bUnit_GetBaseUnit(const void *usys_pt)
{
return ((bUnitCollection *)usys_pt)->base_unit;
}
-const char *bUnit_GetName(void *usys_pt, int index)
+const char *bUnit_GetName(const void *usys_pt, int index)
{
return ((bUnitCollection *)usys_pt)->units[index].name;
}
-const char *bUnit_GetNameDisplay(void *usys_pt, int index)
+const char *bUnit_GetNameDisplay(const void *usys_pt, int index)
{
return ((bUnitCollection *)usys_pt)->units[index].name_display;
}
-double bUnit_GetScaler(void *usys_pt, int index)
+double bUnit_GetScaler(const void *usys_pt, int index)
{
return ((bUnitCollection *)usys_pt)->units[index].scalar;
}