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
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_collection.h6
-rw-r--r--source/blender/blenkernel/BKE_customdata.h6
-rw-r--r--source/blender/blenkernel/BKE_lib_id.h3
-rw-r--r--source/blender/blenkernel/BKE_mesh.h3
-rw-r--r--source/blender/blenkernel/BKE_mesh_mirror.h2
-rw-r--r--source/blender/blenkernel/BKE_multires.h2
-rw-r--r--source/blender/blenkernel/BKE_object.h6
-rw-r--r--source/blender/blenkernel/BKE_paint.h30
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h201
-rw-r--r--source/blender/blenkernel/intern/anim_data.c2
-rw-r--r--source/blender/blenkernel/intern/brush.c8
-rw-r--r--source/blender/blenkernel/intern/customdata.c46
-rw-r--r--source/blender/blenkernel/intern/mesh.c10
-rw-r--r--source/blender/blenkernel/intern/mesh_mirror.c12
-rw-r--r--source/blender/blenkernel/intern/mesh_remesh_voxel.c2
-rw-r--r--source/blender/blenkernel/intern/multires.c448
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_smooth.c33
-rw-r--r--source/blender/blenkernel/intern/multires_unsubdivide.c4
-rw-r--r--source/blender/blenkernel/intern/paint.c37
-rw-r--r--source/blender/blenkernel/intern/pbvh.c657
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c2058
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h25
-rw-r--r--source/blender/blenkernel/intern/scene.c1
-rw-r--r--source/blender/blenkernel/intern/subdiv_displacement_multires.c5
-rw-r--r--source/blender/blenkernel/intern/subdiv_eval.c8
-rw-r--r--source/blender/blenlib/BLI_ghash.h43
-rw-r--r--source/blender/blenlib/intern/BLI_ghash_utils.c121
-rw-r--r--source/blender/blenlib/intern/BLI_mempool.c37
-rw-r--r--source/blender/blenlib/intern/task_pool.cc3
-rw-r--r--source/blender/blenloader/intern/versioning_290.c10
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c8
-rw-r--r--source/blender/bmesh/bmesh_class.h5
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.c534
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.h2
-rw-r--r--source/blender/bmesh/intern/bmesh_log.c457
-rw-r--r--source/blender/bmesh/intern/bmesh_log.h16
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.c8
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c28
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.h5
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_convert.c37
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_convert.h8
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c22
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.c37
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.h43
-rw-r--r--source/blender/bmesh/operators/bmo_mesh_convert.c4
-rw-r--r--source/blender/draw/DRW_engine.h7
-rw-r--r--source/blender/draw/intern/draw_cache.c35
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt1
-rw-r--r--source/blender/editors/include/UI_icons.h2
-rw-r--r--source/blender/editors/mesh/editmesh_mask_extract.c6
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c126
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c4
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c1
-rw-r--r--source/blender/editors/mesh/mesh_intern.h2
-rw-r--r--source/blender/editors/mesh/mesh_ops.c3
-rw-r--r--source/blender/editors/object/object_remesh.c8
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt1
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_hide.c20
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c14
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c1211
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_automasking.c130
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_boundary.c213
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c64
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_detail.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_dyntopo.c246
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_expand.c135
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.c144
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_color.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mask.c14
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mesh.c39
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h152
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_mask_expand.c26
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_paint_color.c27
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_pose.c92
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_smooth.c395
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_transform.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c347
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c5
-rw-r--r--source/blender/gpu/GPU_buffers.h15
-rw-r--r--source/blender/gpu/GPU_vertex_format.h2
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c456
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_mesh.cc2
-rw-r--r--source/blender/io/collada/collada_utils.cpp4
-rw-r--r--source/blender/makesdna/DNA_brush_enums.h10
-rw-r--r--source/blender/makesdna/DNA_brush_types.h6
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h1
-rw-r--r--source/blender/makesdna/DNA_scene_types.h1
-rw-r--r--source/blender/makesrna/intern/rna_brush.c52
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c7
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c20
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c2
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c44
-rw-r--r--source/blender/modifiers/intern/MOD_decimate.c3
-rw-r--r--source/blender/modifiers/intern/MOD_edgesplit.c5
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.c2
-rw-r--r--source/blender/modifiers/intern/MOD_simulation.cc194
-rw-r--r--source/blender/modifiers/intern/MOD_triangulate.c8
-rw-r--r--source/blender/modifiers/intern/MOD_uvwarp.c16
-rw-r--r--source/blender/modifiers/intern/MOD_wireframe.c2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_boolean.cc4
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c8
-rw-r--r--source/blender/render/RE_render_ext.h121
-rw-r--r--source/blender/render/RE_shader_ext.h83
-rw-r--r--source/blender/render/intern/bake_api.c1070
-rw-r--r--source/blender/render/intern/external_engine.c1032
m---------source/tools0
108 files changed, 10335 insertions, 1374 deletions
diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h
index d15aebfe03d..6528c499146 100644
--- a/source/blender/blenkernel/BKE_collection.h
+++ b/source/blender/blenkernel/BKE_collection.h
@@ -26,6 +26,8 @@
#include "BLI_sys_types.h"
#include "DNA_listBase.h"
+#include "DNA_userdef_types.h"
+#include "BKE_lib_id.h"
#ifdef __cplusplus
extern "C" {
@@ -71,8 +73,8 @@ bool BKE_collection_delete(struct Main *bmain, struct Collection *collection, bo
struct Collection *BKE_collection_duplicate(struct Main *bmain,
struct Collection *parent,
struct Collection *collection,
- const uint duplicate_flags,
- const uint duplicate_options);
+ const eDupli_ID_Flags duplicate_flags,
+ const eLibIDDuplicateFlags duplicate_options);
/* Master Collection for Scene */
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index ed319948160..b31f004628d 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -104,6 +104,8 @@ bool CustomData_has_math(const struct CustomData *data);
bool CustomData_has_interp(const struct CustomData *data);
bool CustomData_bmesh_has_free(const struct CustomData *data);
+bool CustomData_layout_is_same(const struct CustomData *_a, const struct CustomData *_b);
+
/**
* Checks if any of the customdata layers is referenced.
*/
@@ -140,6 +142,10 @@ void CustomData_copy(const struct CustomData *source,
/* BMESH_TODO, not really a public function but readfile.c needs it */
void CustomData_update_typemap(struct CustomData *data);
+/* copies all customdata layers without allocating data,
+ * and without respect to type masks or NO_COPY/etc flags*/
+void CustomData_copy_all_layout(const struct CustomData *source, struct CustomData *dest);
+
/* same as the above, except that this will preserve existing layers, and only
* add the layers that were not there yet */
bool CustomData_merge(const struct CustomData *source,
diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h
index 5a8d36b94ec..f6dd3e4fdfc 100644
--- a/source/blender/blenkernel/BKE_lib_id.h
+++ b/source/blender/blenkernel/BKE_lib_id.h
@@ -46,6 +46,7 @@
*/
#include "BLI_compiler_attrs.h"
+#include "DNA_userdef_types.h"
#ifdef __cplusplus
extern "C" {
@@ -243,7 +244,7 @@ struct ID *BKE_id_copy_ex(struct Main *bmain,
const int flag);
struct ID *BKE_id_copy_for_duplicate(struct Main *bmain,
struct ID *id,
- const uint duplicate_flags);
+ const eDupli_ID_Flags duplicate_flags);
void BKE_lib_id_swap(struct Main *bmain, struct ID *id_a, struct ID *id_b);
void BKE_lib_id_swap_full(struct Main *bmain, struct ID *id_a, struct ID *id_b);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index e39caac7c36..8bff9b6ba78 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -69,7 +69,8 @@ extern "C" {
/* *** mesh.c *** */
-struct BMesh *BKE_mesh_to_bmesh_ex(const struct Mesh *me,
+struct BMesh *BKE_mesh_to_bmesh_ex(const struct Object *ob,
+ const struct Mesh *me,
const struct BMeshCreateParams *create_params,
const struct BMeshFromMeshParams *convert_params);
struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me,
diff --git a/source/blender/blenkernel/BKE_mesh_mirror.h b/source/blender/blenkernel/BKE_mesh_mirror.h
index 7b230b04410..b5d0fec6bc1 100644
--- a/source/blender/blenkernel/BKE_mesh_mirror.h
+++ b/source/blender/blenkernel/BKE_mesh_mirror.h
@@ -32,7 +32,7 @@ struct Mesh;
struct MirrorModifierData;
struct Object;
-struct Mesh *BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(struct MirrorModifierData *mmd,
+struct Mesh *BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(struct Object *ob, struct MirrorModifierData *mmd,
const struct Mesh *mesh,
int axis,
const float plane_co[3],
diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h
index fce25abba7f..391d0104be5 100644
--- a/source/blender/blenkernel/BKE_multires.h
+++ b/source/blender/blenkernel/BKE_multires.h
@@ -39,6 +39,7 @@ struct MultiresModifierData;
struct Object;
struct Scene;
struct SubdivCCG;
+struct BMesh;
struct MLoop;
struct MLoopTri;
@@ -217,6 +218,7 @@ BLI_INLINE void BKE_multires_construct_tangent_matrix(float tangent_matrix[3][3]
const float dPdv[3],
const int corner);
+void BKE_multires_bmesh_space_set(struct Object *ob, struct BMesh *bm, int mode);
/* Versioning. */
/* Convert displacement which is stored for simply-subdivided mesh to a Catmull-Clark
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 12c40e891c9..d57469e11c0 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -25,6 +25,8 @@
#include "BLI_sys_types.h"
#include "DNA_object_enums.h"
+#include "DNA_userdef_types.h"
+#include "BKE_lib_id.h"
#ifdef __cplusplus
extern "C" {
@@ -153,8 +155,8 @@ bool BKE_object_obdata_is_libdata(const struct Object *ob);
struct Object *BKE_object_duplicate(struct Main *bmain,
struct Object *ob,
- uint dupflag,
- const uint duplicate_options);
+ eDupli_ID_Flags dupflag,
+ const eLibIDDuplicateFlags duplicate_options);
void BKE_object_obdata_size_init(struct Object *ob, const float size);
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 228b52123f3..3e5bf2570a6 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -27,6 +27,7 @@
#include "BLI_utildefines.h"
#include "DNA_brush_enums.h"
#include "DNA_object_enums.h"
+#include "BKE_pbvh.h"
#ifdef __cplusplus
extern "C" {
@@ -360,7 +361,8 @@ typedef struct SculptVertexInfo {
typedef struct SculptBoundaryEditInfo {
/* Vertex index from where the topology propagation reached this vertex. */
- int original_vertex;
+ SculptVertRef original_vertex;
+ int original_vertex_i;
/* How many steps were needed to reach this vertex from the boundary. */
int num_propagation_steps;
@@ -371,13 +373,15 @@ typedef struct SculptBoundaryEditInfo {
/* Edge for drawing the boundary preview in the cursor. */
typedef struct SculptBoundaryPreviewEdge {
- int v1;
- int v2;
+ SculptVertRef v1;
+ SculptVertRef v2;
} SculptBoundaryPreviewEdge;
typedef struct SculptBoundary {
/* Vertex indices of the active boundary. */
- int *vertices;
+ SculptVertRef *vertices;
+ int *vertex_indices;
+
int vertices_capacity;
int num_vertices;
@@ -395,12 +399,12 @@ typedef struct SculptBoundary {
bool forms_loop;
/* Initial vertex in the boundary which is closest to the current sculpt active vertex. */
- int initial_vertex;
+ SculptVertRef initial_vertex;
/* Vertex that at max_propagation_steps from the boundary and closest to the original active
* vertex that was used to initialize the boundary. This is used as a reference to check how much
* the deformation will go into the mesh and to calculate the strength of the brushes. */
- int pivot_vertex;
+ SculptVertRef pivot_vertex;
/* Stores the initial positions of the pivot and boundary initial vertex as they may be deformed
* during the brush action. This allows to use them as a reference positions and vectors for some
@@ -440,7 +444,7 @@ typedef struct SculptFakeNeighbors {
float current_max_distance;
/* Indexed by vertex, stores the vertex index of its fake neighbor if available. */
- int *fake_neighbor_index;
+ SculptVertRef *fake_neighbor_index;
} SculptFakeNeighbors;
@@ -493,6 +497,9 @@ typedef struct SculptSession {
struct BMesh *bm;
int cd_vert_node_offset;
int cd_face_node_offset;
+ int cd_vcol_offset;
+ int cd_faceset_offset;
+
bool bm_smooth_shading;
/* Undo/redo log for dynamic topology sculpting */
struct BMLog *bm_log;
@@ -520,9 +527,9 @@ typedef struct SculptSession {
struct ExpandCache *expand_cache;
/* Cursor data and active vertex for tools */
- int active_vertex_index;
+ SculptVertRef active_vertex_index;
+ SculptFaceRef active_face_index;
- int active_face_index;
int active_grid_index;
/* When active, the cursor draws with faded colors, indicating that there is an action enabled.
@@ -544,9 +551,12 @@ typedef struct SculptSession {
struct RegionView3D *rv3d;
struct View3D *v3d;
struct Scene *scene;
+ int cd_origvcol_offset;
+ int cd_origco_offset;
+ int cd_origno_offset;
/* Dynamic mesh preview */
- int *preview_vert_index_list;
+ SculptVertRef *preview_vert_index_list;
int preview_vert_index_count;
/* Pose Brush Preview */
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 0fa44067b16..b1d2156f1e4 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -22,20 +22,42 @@
*/
#include "BLI_bitmap.h"
+#include "BLI_compiler_compat.h"
#include "BLI_ghash.h"
/* For embedding CCGKey in iterator. */
#include "BKE_ccg.h"
+#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
+typedef struct {
+ int64_t i;
+} SculptVertRef;
+
+typedef SculptVertRef SculptFaceRef;
+
+BLI_INLINE SculptVertRef BKE_pbvh_make_vref(intptr_t i)
+{
+ SculptVertRef ret = {i};
+ return ret;
+}
+
+BLI_INLINE SculptFaceRef BKE_pbvh_make_fref(intptr_t i)
+{
+ SculptFaceRef ret = {i};
+ return ret;
+}
+
struct BMLog;
struct BMesh;
+struct BMVert;
struct CCGElem;
struct CCGKey;
struct CustomData;
+struct TableGSet;
struct DMFlagMat;
struct GPU_PBVH_Buffers;
struct IsectRayPrecalc;
@@ -52,12 +74,86 @@ struct TaskParallelSettings;
typedef struct PBVH PBVH;
typedef struct PBVHNode PBVHNode;
+//#define PROXY_ADVANCED
+
+// experimental performance test of "data-based programming" approach
+#ifdef PROXY_ADVANCED
+typedef struct ProxyKey {
+ int node;
+ int pindex;
+} ProxyKey;
+
+# define MAX_PROXY_NEIGHBORS 12
+
+typedef struct ProxyVertArray {
+ float **ownerco;
+ short **ownerno;
+ float (*co)[3];
+ float (*fno)[3];
+ short (*no)[3];
+ float *mask, **ownermask;
+ SculptVertRef *index;
+ float **ownercolor, (*color)[4];
+
+ ProxyKey (*neighbors)[MAX_PROXY_NEIGHBORS];
+
+ int size;
+ int datamask;
+ bool neighbors_dirty;
+
+ GHash *indexmap;
+} ProxyVertArray;
+
+typedef enum {
+ PV_OWNERCO = 1,
+ PV_OWNERNO = 2,
+ PV_CO = 4,
+ PV_NO = 8,
+ PV_MASK = 16,
+ PV_OWNERMASK = 32,
+ PV_INDEX = 64,
+ PV_OWNERCOLOR = 128,
+ PV_COLOR = 256,
+ PV_NEIGHBORS = 512
+} ProxyVertField;
+
+typedef struct ProxyVertUpdateRec {
+ float *co, *no, *mask, *color;
+ SculptVertRef index, newindex;
+} ProxyVertUpdateRec;
+
+# define PBVH_PROXY_DEFAULT CO | INDEX | MASK
+
+struct SculptSession;
+
+void BKE_pbvh_ensure_proxyarrays(
+ struct SculptSession *ss, PBVH *pbvh, PBVHNode **nodes, int totnode, int mask);
+void BKE_pbvh_load_proxyarrays(PBVH *pbvh, PBVHNode **nodes, int totnode, int mask);
+
+void BKE_pbvh_ensure_proxyarray(
+ struct SculptSession *ss,
+ struct PBVH *pbvh,
+ struct PBVHNode *node,
+ int mask,
+ struct GHash
+ *vert_node_map, // vert_node_map maps vertex SculptVertRefs to PBVHNode indices; optional
+ bool check_indexmap,
+ bool force_update);
+void BKE_pbvh_gather_proxyarray(PBVH *pbvh, PBVHNode **nodes, int totnode);
+
+void BKE_pbvh_free_proxyarray(struct PBVH *pbvh, struct PBVHNode *node);
+void BKE_pbvh_update_proxyvert(struct PBVH *pbvh, struct PBVHNode *node, ProxyVertUpdateRec *rec);
+ProxyVertArray *BKE_pbvh_get_proxyarrays(struct PBVH *pbvh, struct PBVHNode *node);
+
+#endif
+
typedef struct {
float (*co)[3];
} PBVHProxyNode;
typedef struct {
float (*color)[4];
+ int size;
} PBVHColorBufferNode;
typedef enum {
@@ -78,6 +174,7 @@ typedef enum {
PBVH_UpdateTopology = 1 << 13,
PBVH_UpdateColor = 1 << 14,
+ PBVH_Delete = 1 << 15
} PBVHNodeFlags;
typedef struct PBVHFrustumPlanes {
@@ -98,6 +195,8 @@ typedef void (*BKE_pbvh_HitOccludedCallback)(PBVHNode *node, void *data, float *
typedef void (*BKE_pbvh_SearchNearestCallback)(PBVHNode *node, void *data, float *tmin);
+void BKE_pbvh_get_nodes(PBVH *pbvh, int flag, PBVHNode ***r_array, int *r_totnode);
+
/* Building */
PBVH *BKE_pbvh_new(void);
@@ -124,9 +223,24 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh,
bool smooth_shading,
struct BMLog *log,
const int cd_vert_node_offset,
- const int cd_face_node_offset);
+ const int cd_face_node_offset,
+ const int cd_origco_offset,
+ const int cd_origno_offset,
+ const int cd_origvcol_offset);
+void BKE_pbvh_update_offsets(PBVH *pbvh,
+ const int cd_vert_node_offset,
+ const int cd_face_node_offset,
+ const int cd_origco_offset,
+ const int cd_origno_offset,
+ const int cd_origvcol_offset);
void BKE_pbvh_free(PBVH *pbvh);
+/** update original data, only data whose r_** parameters are passed in will be updated*/
+void BKE_pbvh_bmesh_update_origvert(
+ PBVH *pbvh, struct BMVert *v, float **r_co, float **r_no, float **r_color);
+void BKE_pbvh_update_origcolor_bmesh(PBVH *pbvh, PBVHNode *node);
+void BKE_pbvh_update_origco_bmesh(PBVH *pbvh, PBVHNode *node);
+
/* Hierarchical Search in the BVH, two methods:
* - for each hit calling a callback
* - gather nodes in an array (easy to multithread) */
@@ -160,8 +274,8 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh,
const float ray_normal[3],
struct IsectRayPrecalc *isect_precalc,
float *depth,
- int *active_vertex_index,
- int *active_face_grid_index,
+ SculptVertRef *active_vertex_index,
+ SculptFaceRef *active_face_grid_index,
float *face_normal);
bool BKE_pbvh_bmesh_node_raycast_detail(PBVHNode *node,
@@ -250,8 +364,22 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
const float view_normal[3],
float radius,
const bool use_frontface,
- const bool use_projected);
-
+ const bool use_projected,
+ int symaxis,
+ bool updatePBVH);
+
+bool BKE_pbvh_bmesh_update_topology_nodes(PBVH *pbvh,
+ bool (*searchcb)(PBVHNode *node, void *data),
+ void (*undopush)(PBVHNode *node, void *data),
+ void *searchdata,
+ PBVHTopologyUpdateMode mode,
+ const float center[3],
+ const float view_normal[3],
+ float radius,
+ const bool use_frontface,
+ const bool use_projected,
+ int sym_axis,
+ bool updatePBVH);
/* Node Access */
void BKE_pbvh_node_mark_update(PBVHNode *node);
@@ -292,10 +420,10 @@ bool BKE_pbvh_node_frustum_contain_AABB(PBVHNode *node, void *frustum);
/* test if AABB is at least partially outside the PBVHFrustumPlanes volume */
bool BKE_pbvh_node_frustum_exclude_AABB(PBVHNode *node, void *frustum);
-struct GSet *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node);
-struct GSet *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node);
-struct GSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node);
-void BKE_pbvh_bmesh_node_save_orig(struct BMesh *bm, PBVHNode *node);
+struct TableGSet *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node);
+struct TableGSet *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node);
+struct TableGSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node);
+void BKE_pbvh_bmesh_node_save_ortri(struct BMesh *bm, PBVHNode *node);
void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh);
/* Update Bounding Box/Redraw and clear flags */
@@ -343,6 +471,7 @@ typedef struct PBVHVertexIter {
int gy;
int i;
int index;
+ SculptVertRef vertex;
bool respect_hide;
/* grid */
@@ -362,10 +491,13 @@ typedef struct PBVHVertexIter {
float *vmask;
/* bmesh */
- struct GSetIterator bm_unique_verts;
- struct GSetIterator bm_other_verts;
+ int bi;
+ struct TableGSet *bm_cur_set;
+ struct TableGSet *bm_unique_verts, *bm_other_verts;
+
struct CustomData *bm_vdata;
int cd_vert_mask_offset;
+ int cd_vcol_offset;
/* result: these are all computed in the macro, but we assume
* that compiler optimization's will skip the ones we don't use */
@@ -388,7 +520,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
if (vi.grids) { \
vi.width = vi.gridsize; \
vi.height = vi.gridsize; \
- vi.index = vi.grid_indices[vi.g] * vi.key.grid_area - 1; \
+ vi.vertex.i = vi.index = vi.grid_indices[vi.g] * vi.key.grid_area - 1; \
vi.grid = vi.grids[vi.grid_indices[vi.g]]; \
if (mode == PBVH_ITER_UNIQUE) { \
vi.gh = vi.grid_hidden[vi.grid_indices[vi.g]]; \
@@ -407,6 +539,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
vi.mask = vi.key.has_mask ? CCG_elem_mask(&vi.key, vi.grid) : NULL; \
vi.grid = CCG_elem_next(&vi.key, vi.grid); \
vi.index++; \
+ vi.vertex.i++; \
vi.visible = true; \
if (vi.gh) { \
if (BLI_BITMAP_TEST(vi.gh, vi.gy * vi.gridsize + vi.gx)) { \
@@ -427,7 +560,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
} \
vi.co = vi.mvert->co; \
vi.no = vi.mvert->no; \
- vi.index = vi.vert_indices[vi.i]; \
+ vi.index = vi.vertex.i = vi.vert_indices[vi.i]; \
if (vi.vmask) { \
vi.mask = &vi.vmask[vi.index]; \
} \
@@ -436,21 +569,40 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
} \
} \
else { \
- if (!BLI_gsetIterator_done(&vi.bm_unique_verts)) { \
- vi.bm_vert = BLI_gsetIterator_getKey(&vi.bm_unique_verts); \
- BLI_gsetIterator_step(&vi.bm_unique_verts); \
+ BMVert *bv = NULL; \
+ while (!bv) { \
+ if (!vi.bm_cur_set->elems || vi.bi >= vi.bm_cur_set->cur) { \
+ if (vi.bm_cur_set != vi.bm_other_verts && mode != PBVH_ITER_UNIQUE) { \
+ vi.bm_cur_set = vi.bm_other_verts; \
+ vi.bi = 0; \
+ if (!vi.bm_cur_set->elems || vi.bi >= vi.bm_other_verts->cur) { \
+ break; \
+ } \
+ } \
+ else { \
+ break; \
+ } \
+ } \
+ else { \
+ bv = vi.bm_cur_set->elems[vi.bi++]; \
+ } \
} \
- else { \
- vi.bm_vert = BLI_gsetIterator_getKey(&vi.bm_other_verts); \
- BLI_gsetIterator_step(&vi.bm_other_verts); \
+ if (!bv) { \
+ continue; \
} \
+ vi.bm_vert = bv; \
+ if (vi.cd_vcol_offset >= 0) { \
+ MPropCol *vcol = BM_ELEM_CD_GET_VOID_P(bv, vi.cd_vcol_offset); \
+ vi.col = vcol->color; \
+ } \
+ vi.vertex.i = (intptr_t)bv; \
+ vi.index = BM_elem_index_get(vi.bm_vert); \
vi.visible = !BM_elem_flag_test_bool(vi.bm_vert, BM_ELEM_HIDDEN); \
if (mode == PBVH_ITER_UNIQUE && !vi.visible) { \
continue; \
} \
vi.co = vi.bm_vert->co; \
vi.fno = vi.bm_vert->no; \
- vi.index = BM_elem_index_get(vi.bm_vert); \
vi.mask = BM_ELEM_CD_GET_VOID_P(vi.bm_vert, vi.cd_vert_mask_offset); \
}
@@ -460,6 +612,10 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
} \
((void)0)
+#define BKE_pbvh_vertex_index_to_table(pbvh, v) \
+ (BKE_pbvh_type(pbvh) == PBVH_BMESH && v.i != -1 ? BM_elem_index_get((BMVert *)(v.i)) : (v.i))
+SculptVertRef BKE_pbvh_table_index_to_vertex(PBVH *pbvh, int idx);
+
void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *proxy_count);
void BKE_pbvh_node_free_proxies(PBVHNode *node);
PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *pbvh, PBVHNode *node);
@@ -490,6 +646,11 @@ struct MVert *BKE_pbvh_get_verts(const PBVH *pbvh);
PBVHColorBufferNode *BKE_pbvh_node_color_buffer_get(PBVHNode *node);
void BKE_pbvh_node_color_buffer_free(PBVH *pbvh);
+int BKE_pbvh_get_node_index(PBVH *pbvh, PBVHNode *node);
+void BKE_pbvh_set_flat_vcol_shading(PBVH *pbvh, bool value);
+
+#define DYNTOPO_CD_INTERP
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c
index 633d6202222..521ebbfaf97 100644
--- a/source/blender/blenkernel/intern/anim_data.c
+++ b/source/blender/blenkernel/intern/anim_data.c
@@ -423,7 +423,7 @@ void BKE_animdata_copy_id_action(Main *bmain, ID *id)
void BKE_animdata_duplicate_id_action(struct Main *bmain,
struct ID *id,
- const eDupli_ID_Flags duplicate_flags)
+ const uint duplicate_flags)
{
if (duplicate_flags & USER_DUP_ACT) {
animdata_copy_id_action(bmain, id, true, (duplicate_flags & USER_DUP_LINKED_ID) != 0);
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 13ba1957a32..3b5b16feea8 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -1839,6 +1839,13 @@ void BKE_brush_sculpt_reset(Brush *br)
br->flag &= ~BRUSH_SPACE_ATTEN;
br->curve_preset = BRUSH_CURVE_SPHERE;
break;
+ case SCULPT_TOOL_VCOL_BOUNDARY:
+ br->flag &= ~BRUSH_SPACE_ATTEN;
+ br->spacing = 5;
+ br->alpha = 0.7f;
+ br->surface_smooth_shape_preservation = 0.5f;
+ br->surface_smooth_current_vertex = 0.5f;
+ br->surface_smooth_iterations = 4;
case SCULPT_TOOL_DISPLACEMENT_SMEAR:
br->alpha = 1.0f;
br->spacing = 5;
@@ -1906,6 +1913,7 @@ void BKE_brush_sculpt_reset(Brush *br)
br->sub_col[2] = 0.005f;
break;
+ case SCULPT_TOOL_VCOL_BOUNDARY:
case SCULPT_TOOL_SIMPLIFY:
case SCULPT_TOOL_PAINT:
case SCULPT_TOOL_MASK:
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index d8d9675b42b..571010e2017 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -72,6 +72,32 @@ BLI_STATIC_ASSERT(ARRAY_SIZE(((CustomData *)NULL)->typemap) == CD_NUMTYPES, "siz
static CLG_LogRef LOG = {"bke.customdata"};
+bool CustomData_layout_is_same(const CustomData *_a, const CustomData *_b)
+{
+ CustomData a = *_a;
+ CustomData b = *_b;
+
+ a.layers = b.layers = NULL;
+ a.pool = b.pool = NULL;
+
+ if (memcmp((void *)&a, (void *)&b, sizeof(CustomData)) != 0) {
+ return false;
+ }
+
+ for (int i = 0; i < a.totlayer; i++) {
+ CustomDataLayer cla = _a->layers[i];
+ CustomDataLayer clb = _b->layers[i];
+
+ cla.data = clb.data = NULL;
+
+ if (memcmp((void *)&cla, (void *)&clb, sizeof(CustomDataLayer)) != 0) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
/** Update mask_dst with layers defined in mask_src (equivalent to a bitwise OR). */
void CustomData_MeshMasks_update(CustomData_MeshMasks *mask_dst,
const CustomData_MeshMasks *mask_src)
@@ -2095,6 +2121,26 @@ static bool customdata_typemap_is_valid(const CustomData *data)
}
#endif
+/* copies all customdata layers without allocating data,
+ * and without respect to type masks or NO_COPY/etc flags*/
+void CustomData_copy_all_layout(const struct CustomData *source, struct CustomData *dest)
+{
+ *dest = *source;
+
+ if (dest->pool) {
+ dest->pool = NULL;
+ }
+
+ if (source->layers) {
+ dest->layers = MEM_mallocN(sizeof(*dest->layers) * source->totlayer, __func__);
+
+ for (int i = 0; i < source->totlayer; i++) {
+ dest->layers[i] = source->layers[i];
+ dest->layers[i].data = NULL;
+ }
+ }
+}
+
bool CustomData_merge(const struct CustomData *source,
struct CustomData *dest,
CustomDataMask mask,
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index e7a16463d87..5d5d2222f63 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -1004,14 +1004,15 @@ Mesh *BKE_mesh_copy_for_eval(struct Mesh *source, bool reference)
return result;
}
-BMesh *BKE_mesh_to_bmesh_ex(const Mesh *me,
+BMesh *BKE_mesh_to_bmesh_ex(const Object *ob,
+ const Mesh *me,
const struct BMeshCreateParams *create_params,
const struct BMeshFromMeshParams *convert_params)
{
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me);
BMesh *bm = BM_mesh_create(&allocsize, create_params);
- BM_mesh_bm_from_me(bm, me, convert_params);
+ BM_mesh_bm_from_me(ob, bm, me, convert_params);
return bm;
}
@@ -1021,7 +1022,8 @@ BMesh *BKE_mesh_to_bmesh(Mesh *me,
const bool add_key_index,
const struct BMeshCreateParams *params)
{
- return BKE_mesh_to_bmesh_ex(me,
+ return BKE_mesh_to_bmesh_ex(ob,
+ me,
params,
&(struct BMeshFromMeshParams){
.calc_face_normal = false,
@@ -1037,7 +1039,7 @@ Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm,
{
BLI_assert(params->calc_object_remap == false);
Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL);
- BM_mesh_bm_to_me(NULL, bm, mesh, params);
+ BM_mesh_bm_to_me(NULL, NULL, bm, mesh, params);
BKE_mesh_copy_settings(mesh, me_settings);
return mesh;
}
diff --git a/source/blender/blenkernel/intern/mesh_mirror.c b/source/blender/blenkernel/intern/mesh_mirror.c
index a22b52d68d5..d796254f306 100644
--- a/source/blender/blenkernel/intern/mesh_mirror.c
+++ b/source/blender/blenkernel/intern/mesh_mirror.c
@@ -41,7 +41,8 @@
#include "MOD_modifiertypes.h"
-Mesh *BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(MirrorModifierData *mmd,
+Mesh *BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(Object *ob,
+ MirrorModifierData *mmd,
const Mesh *mesh,
int axis,
const float plane_co[3],
@@ -58,7 +59,8 @@ Mesh *BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(MirrorModifierData *mm
BMIter viter;
BMVert *v, *v_next;
- bm = BKE_mesh_to_bmesh_ex(mesh,
+ bm = BKE_mesh_to_bmesh_ex(ob,
+ mesh,
&(struct BMeshCreateParams){0},
&(struct BMeshFromMeshParams){
.calc_face_normal = true,
@@ -102,7 +104,8 @@ void BKE_mesh_mirror_apply_mirror_on_axis(struct Main *bmain,
const int axis,
const float dist)
{
- BMesh *bm = BKE_mesh_to_bmesh_ex(mesh,
+ BMesh *bm = BKE_mesh_to_bmesh_ex(NULL,
+ mesh,
&(struct BMeshCreateParams){
.use_toolflags = 1,
},
@@ -121,6 +124,7 @@ void BKE_mesh_mirror_apply_mirror_on_axis(struct Main *bmain,
true);
BM_mesh_bm_to_me(bmain,
+ NULL,
bm,
mesh,
(&(struct BMeshToMeshParams){
@@ -194,7 +198,7 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
Mesh *mesh_bisect = NULL;
if (do_bisect) {
mesh_bisect = BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(
- mmd, mesh, axis, plane_co, plane_no);
+ ob, mmd, mesh, axis, plane_co, plane_no);
mesh = mesh_bisect;
}
diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.c b/source/blender/blenkernel/intern/mesh_remesh_voxel.c
index 0a5aa360553..3b3a6af9db9 100644
--- a/source/blender/blenkernel/intern/mesh_remesh_voxel.c
+++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.c
@@ -443,7 +443,7 @@ struct Mesh *BKE_mesh_remesh_voxel_fix_poles(struct Mesh *mesh)
.use_toolflags = true,
}));
- BM_mesh_bm_from_me(bm,
+ BM_mesh_bm_from_me(NULL, bm,
mesh,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index 45ac20ef154..30a80576921 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -33,22 +33,31 @@
#include "BLI_bitmap.h"
#include "BLI_blenlib.h"
+#include "BLI_edgehash.h"
#include "BLI_math.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
#include "BKE_ccg.h"
#include "BKE_cdderivedmesh.h"
+#include "BKE_collection.h"
+#include "BKE_context.h"
#include "BKE_editmesh.h"
+#include "BKE_global.h"
+#include "BKE_layer.h"
+#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
+#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
#include "BKE_scene.h"
+#include "BKE_subdiv.h"
#include "BKE_subdiv_ccg.h"
+#include "BKE_subdiv_eval.h"
#include "BKE_subsurf.h"
#include "BKE_object.h"
@@ -57,6 +66,8 @@
#include "DEG_depsgraph_query.h"
+#include "bmesh.h"
+#include "multires_inline.h"
#include "multires_reshape.h"
#include <math.h>
@@ -852,17 +863,448 @@ static void grid_tangent_matrix(float mat[3][3], const CCGKey *key, int x, int y
typedef struct MultiresThreadedData {
DispOp op;
+ MultiResSpace bmop;
+ BMesh *bm;
+ int lvl;
CCGElem **gridData, **subGridData;
CCGKey *key;
CCGKey *sub_key;
+ Subdiv *sd;
MPoly *mpoly;
MDisps *mdisps;
GridPaintMask *grid_paint_mask;
int *gridOffset;
+ int cd_mdisps_off, cd_mask_off;
int gridSize, dGridSize, dSkip;
float (*smat)[3];
+ bool has_grid_mask;
} MultiresThreadedData;
+Object *multires_dump_grids_bmesh(Object *bmob, BMesh *bm)
+{
+ if (!CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
+ printf("multires_dump_grids_bmesh: error: no multires grids\n");
+ return NULL;
+ }
+
+ bool spaceset = false;
+
+ if (bm->multiresSpace != MULTIRES_SPACE_ABSOLUTE) {
+ BKE_multires_bmesh_space_set(bmob, bm, MULTIRES_SPACE_ABSOLUTE);
+ spaceset = true;
+ }
+
+ Main *bmain = G.main;
+ char *name = "multires_dump";
+
+ bContext *ctx = CTX_create();
+ CTX_data_main_set(ctx, bmain);
+ CTX_wm_manager_set(ctx, G.main->wm.first);
+ CTX_data_scene_set(ctx, G.main->scenes.first);
+
+ ViewLayer *view_layer = CTX_data_view_layer(ctx);
+ Object *ob = BKE_object_add_only_object(bmain, OB_MESH, name);
+ LayerCollection *layer_collection;
+
+ ob->data = BKE_object_obdata_add_from_type(bmain, OB_MESH, name);
+ DEG_id_tag_update_ex(
+ bmain, &ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
+ // DEG_id_tag_update_ex(
+ // bmain, &ob->data, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
+
+ layer_collection = BKE_layer_collection_get_active(view_layer);
+ BKE_collection_object_add(bmain, layer_collection->collection, ob);
+
+ DEG_id_type_tag(bmain, ID_OB);
+ DEG_relations_tag_update(bmain);
+ if (ob->data != NULL) {
+ DEG_id_tag_update_ex(bmain, (ID *)ob->data, ID_RECALC_EDITORS);
+ }
+
+ ob->modifiers.first = ob->modifiers.last = NULL;
+ zero_v3(ob->loc);
+
+ printf("users: %d\n", ob->id.us);
+
+ Mesh *me = ob->data;
+
+ BMIter iter;
+ BMFace *f;
+
+ int cd_mdisp_off = CustomData_get_offset(&bm->ldata, CD_MDISPS);
+ int dimen = 0;
+
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ BMLoop *l = f->l_first;
+ MDisps *md = BM_ELEM_CD_GET_VOID_P(l, cd_mdisp_off);
+ dimen = (int)floor(sqrt(md->totdisp) + 0.00001);
+ break;
+ }
+
+ if (!dimen) {
+ printf("multires_dump_grids_bmesh: error: corrupted multires data\n");
+ return NULL;
+ }
+
+ int totvert = bm->totloop * dimen * dimen;
+ int totface = bm->totloop * (dimen - 1) * (dimen - 1);
+ int totloop = totface * 4;
+
+ CustomData_free(&me->vdata, me->totvert);
+ CustomData_free(&me->edata, me->totedge);
+ CustomData_free(&me->fdata, me->totface);
+ CustomData_free(&me->ldata, me->totloop);
+ CustomData_free(&me->pdata, me->totpoly);
+
+ me->totvert = totvert;
+ me->totpoly = totface;
+ me->totloop = totloop;
+ me->totedge = totvert + totface;
+ me->totface = 0;
+ me->act_face = -1;
+
+ EdgeHash *eh = BLI_edgehash_new_ex("multires_dump_bmesh", me->totedge);
+
+ MVert *mvert = me->totvert ?
+ MEM_callocN(sizeof(MVert) * me->totvert, "multires_dump_grids_bmesh.vert") :
+ NULL;
+ MEdge *medge = me->totedge ?
+ MEM_callocN(sizeof(MEdge) * me->totedge, "multires_dump_grids_bmesh.edge") :
+ NULL;
+ MLoop *mloop = me->totloop ?
+ MEM_callocN(sizeof(MLoop) * me->totloop, "multires_dump_grids_bmesh.loop") :
+ NULL;
+ MPoly *mpoly = me->totpoly ?
+ MEM_callocN(sizeof(MPoly) * me->totpoly, "multires_dump_grids_bmesh.poly") :
+ NULL;
+
+ me->cd_flag = 0;
+
+ CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, mvert, me->totvert);
+ CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, medge, me->totedge);
+ CustomData_add_layer(&me->ldata, CD_MLOOP, CD_ASSIGN, mloop, me->totloop);
+ CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, mpoly, me->totpoly);
+
+ BKE_mesh_update_customdata_pointers(me, 0);
+
+ int loopi = 0;
+ int outli = 0;
+ int medi = 0;
+
+#define VINDEX(i, j) (loopi * dimen * dimen + ((j)*dimen + (i)))
+
+ // CustomData_daata_
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ BMLoop *l = f->l_first;
+ do {
+ MDisps *md = BM_ELEM_CD_GET_VOID_P(l, cd_mdisp_off);
+
+ for (int i = 0; i < dimen; i++) {
+ for (int j = 0; j < dimen; j++) {
+ int vidx = loopi * dimen * dimen + (j * dimen + i);
+ int idx = j * dimen + i;
+ float *co = md->disps[idx];
+
+ MVert *mv = mvert + vidx;
+ copy_v3_v3(mv->co, co);
+ }
+ }
+
+ for (int i = 0; i < dimen - 1; i++) {
+ for (int j = 0; j < dimen - 1; j++) {
+ // do face
+ int fidx = loopi * (dimen - 1) * (dimen - 1) + (j * (dimen - 1) + i);
+ MPoly *mp = mpoly + fidx;
+
+ mp->totloop = 4;
+ mp->loopstart = outli;
+
+ MLoop *ml = mloop + outli;
+
+ ml[0].v = VINDEX(i, j);
+ ml[1].v = VINDEX(i, j + 1);
+ ml[2].v = VINDEX(i + 1, j + 1);
+ ml[3].v = VINDEX(i + 1, j);
+
+ for (int i2 = 0; i2 < 4; i2++) {
+ int a = ml[i2].v, b = ml[(i2 + 1) % 4].v;
+ int e;
+
+ if (!BLI_edgehash_haskey(eh, a, b)) {
+ BLI_edgehash_insert(eh, a, b, (void *)medi);
+ e = medi;
+
+ MEdge *med = medge + medi;
+
+ med->v1 = a;
+ med->v2 = b;
+
+ medi++;
+ }
+ else {
+ e = (int)BLI_edgehash_lookup(eh, a, b);
+ }
+
+ ml[i2].e = e;
+ }
+
+ outli += 4;
+ }
+ }
+
+ loopi++;
+ l = l->next;
+ } while (l != f->l_first);
+ }
+
+ for (int i = 0; i < me->totpoly; i++) {
+ if (!mpoly[i].totloop) {
+ printf("error 1! %d %d\n", i, me->totpoly);
+ }
+ if (mpoly[i].loopstart >= me->totloop) {
+ printf(
+ "error 2! %d %d l: %d totl: %d\n", i, me->totpoly, mpoly[i].loopstart, mpoly[i].totloop);
+ }
+ }
+
+ if (spaceset) {
+ BKE_multires_bmesh_space_set(bmob, bm, MULTIRES_SPACE_TANGENT);
+ }
+
+ BKE_mesh_calc_normals(me);
+ BKE_mesh_tessface_calc(me);
+
+ return ob;
+}
+
+static void multires_bmesh_space_set_cb(void *__restrict userdata,
+ const int pidx,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ MultiresThreadedData *tdata = userdata;
+
+ int cd_mdisps_off = tdata->cd_mdisps_off;
+ // int cd_mask_off = tdata->cd_mask_off;
+ BMesh *bm = tdata->bm;
+ MultiResSpace op = tdata->bmop;
+ BMFace *f = bm->ftable[pidx];
+ int gridSize = tdata->gridSize;
+
+ int S, x, y;
+
+ BMLoop *l = f->l_first;
+ float cent[3];
+ int tot = 0;
+
+ // get face center to calculate maximum allowable displacement length
+ zero_v3(cent);
+ do {
+ add_v3_v3(cent, l->v->co);
+ tot++;
+ l = l->next;
+ } while (l != f->l_first);
+
+ mul_v3_fl(cent, 1.0f / (float)tot);
+
+ // bool has_grid_mask = tdata->has_grid_mask;
+
+ l = f->l_first;
+ S = 0;
+ do {
+ // GridPaintMask *gpm = has_grid_mask ? BM_ELEM_CD_GET_VOID_P(l, cd_mask_off) : NULL;
+ MDisps *mdisp = BM_ELEM_CD_GET_VOID_P(l, cd_mdisps_off);
+ float(*dispgrid)[3] = NULL;
+
+ dispgrid = mdisp->disps;
+
+ float maxlen = len_v3v3(l->v->co, cent) * 15.0f;
+ maxlen = MAX2(maxlen, 0.00001f);
+
+ for (y = 0; y < gridSize; y++) {
+ for (x = 0; x < gridSize; x++) {
+ float sco[8], udv[3], vdv[3];
+ float *data = dispgrid[gridSize * y + x];
+ float mat[3][3], disp[3];
+
+ float grid_u = (float)x / (float)(gridSize - 1);
+ float grid_v = (float)y / (float)(gridSize - 1);
+ float u, v;
+
+ int corner = S;
+ if (f->len == 4) {
+ BKE_subdiv_rotate_grid_to_quad(corner, grid_u, grid_v, &u, &v);
+ }
+ else {
+ u = 1.0 - grid_v;
+ v = 1.0 - grid_u;
+ }
+
+ BKE_subdiv_eval_limit_point_and_derivatives(tdata->sd, l->head.index, u, v, sco, udv, vdv);
+ BKE_multires_construct_tangent_matrix(mat, udv, vdv, f->len == 4 ? corner : 0);
+
+ copy_v3_v3(disp, data);
+
+ switch (op) {
+ case MULTIRES_SPACE_ABSOLUTE:
+ /* Convert displacement to object space
+ * and add to grid points */
+ mul_v3_m3v3(disp, mat, data);
+ add_v3_v3v3(data, disp, sco);
+ break;
+ case MULTIRES_SPACE_TANGENT:
+ /* Calculate displacement between new and old
+ * grid points and convert to tangent space */
+ invert_m3(mat);
+
+ sub_v3_v3v3(disp, data, sco);
+ mul_v3_m3v3(data, mat, disp);
+
+ // try to prevent errors
+ float len = len_v3(data);
+ if (len > maxlen) {
+ mul_v3_fl(data, maxlen/len);
+ } else if (isnan(len)) {
+ zero_v3(data);
+ }
+ break;
+ }
+ }
+ }
+
+ S++;
+ l = l->next;
+ } while (l != f->l_first);
+}
+
+/* XXX WARNING: subsurf elements from dm and oldGridData *must* be of the same format (size),
+ * because this code uses CCGKey's info from dm to access oldGridData's normals
+ * (through the call to grid_tangent_matrix())! */
+void BKE_multires_bmesh_space_set(Object *ob, BMesh *bm, int mode)
+{
+ if (!bm->totface || !CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
+ return;
+ }
+
+ MultiresModifierData *mmd = bm->haveMultiResSettings ? &bm->multires : NULL;
+
+ if (!mmd && ob) {
+ mmd = get_multires_modifier(NULL, ob, true);
+ }
+
+ if (!mmd || !CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
+ return;
+ }
+
+ bm->multiresSpace = mode;
+
+ Mesh _me, *me = &_me;
+ memset(me, 0, sizeof(Mesh));
+ CustomData_reset(&me->vdata);
+ CustomData_reset(&me->edata);
+ CustomData_reset(&me->ldata);
+ CustomData_reset(&me->fdata);
+ CustomData_reset(&me->pdata);
+
+ CustomData_MeshMasks extra = CD_MASK_DERIVEDMESH;
+ extra.lmask |= CD_MASK_MDISPS;
+
+ // CustomData_MeshMasks extra = {0};
+ BM_mesh_bm_to_me_for_eval(bm, me, &extra);
+ SubdivSettings settings2;
+
+ // ensure we control the level
+ MultiresModifierData mmdcpy = *mmd;
+ mmdcpy.lvl = mmdcpy.sculptlvl = mmdcpy.renderlvl = mmdcpy.totlvl;
+
+ BKE_multires_subdiv_settings_init(&settings2, &mmdcpy);
+ Subdiv *sd = BKE_subdiv_new_from_mesh(&settings2, me);
+ BKE_subdiv_eval_begin_from_mesh(sd, me, NULL);
+
+ Object fakeob;
+ if (ob) {
+ fakeob = *ob;
+ fakeob.sculpt = NULL;
+ }
+ else {
+ memset(&fakeob, 0, sizeof(fakeob));
+ fakeob.data = me;
+ BLI_addtail(&fakeob.modifiers, &mmdcpy);
+ }
+
+ int i, gridSize, dGridSize, dSkip;
+ int totpoly = bm->totface;
+
+ // paranoia recalc of indices/lookup tables
+ bm->elem_index_dirty |= BM_FACE;
+ bm->elem_table_dirty |= BM_FACE;
+
+ BM_mesh_elem_index_ensure(bm, BM_FACE);
+ BM_mesh_elem_table_ensure(bm, BM_FACE);
+
+ gridSize = multires_side_tot[mmd->totlvl];
+
+ /* when adding new faces in edit mode, need to allocate disps */
+ int cd_disp_off = CustomData_get_offset(&bm->ldata, CD_MDISPS);
+
+ BMFace *f;
+ BMIter iter;
+ i = 0;
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ BMIter iter2;
+ BMLoop *l;
+
+ f->head.index = i;
+
+ BM_ITER_ELEM (l, &iter2, f, BM_LOOPS_OF_FACE) {
+ MDisps *mdisp = BM_ELEM_CD_GET_VOID_P(l, cd_disp_off);
+ if (!mdisp->disps) {
+ multires_reallocate_mdisps(1, mdisp, mmd->totlvl);
+ }
+
+ l->head.index = i;
+
+ if (f->len != 4) {
+ i++;
+ }
+ }
+
+ if (f->len == 4) {
+ i++;
+ }
+ }
+
+ TaskParallelSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = CCG_TASK_LIMIT;
+
+ bool has_grid_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK);
+
+ MultiresThreadedData data = {
+ .bmop = mode,
+ .sd = sd,
+ .lvl = mmd->totlvl,
+ .bm = bm,
+ .cd_mdisps_off = cd_disp_off,
+ .cd_mask_off = has_grid_mask ? CustomData_get_offset(&bm->ldata, CD_GRID_PAINT_MASK) : -1,
+ .has_grid_mask = has_grid_mask,
+ .gridSize = gridSize,
+ };
+
+ BLI_task_parallel_range(0, totpoly, &data, multires_bmesh_space_set_cb, &settings);
+
+ // MDisps = CustomData_get
+ // if (mode == MULTIRES_SPACE_TANGENT) {
+ // ccgSubSurf_stitchFaces(ccgdm->ss, 0, NULL, 0);
+ // ccgSubSurf_updateNormals(ccgdm->ss, NULL, 0);
+ //}
+
+ BKE_mesh_free(me);
+ BKE_subdiv_free(sd);
+
+ bm->elem_index_dirty |= BM_FACE|BM_LOOP;
+ bm->elem_table_dirty |= BM_FACE|BM_LOOP;
+}
+
static void multires_disp_run_cb(void *__restrict userdata,
const int pidx,
const TaskParallelTLS *__restrict UNUSED(tls))
@@ -1224,7 +1666,7 @@ void multires_stitch_grids(Object *ob)
int num_faces;
BKE_pbvh_get_grid_updates(pbvh, false, (void ***)&faces, &num_faces);
if (num_faces) {
- BKE_subdiv_ccg_average_stitch_faces(subdiv_ccg, faces, num_faces);
+ // XXX BKE_subdiv_ccg_average_stitch_faces(subdiv_ccg, faces, num_faces);
MEM_freeN(faces);
}
}
@@ -1340,7 +1782,7 @@ void old_mdisps_bilinear(float out[3], float (*disps)[3], const int st, float u,
urat = u - x;
vrat = v - y;
- uopp = 1 - urat;
+ uopp = 1.0f - urat;
mul_v3_v3fl(d[0], disps[y * st + x], uopp);
mul_v3_v3fl(d[1], disps[y * st + x2], urat);
@@ -1349,7 +1791,7 @@ void old_mdisps_bilinear(float out[3], float (*disps)[3], const int st, float u,
add_v3_v3v3(d2[0], d[0], d[1]);
add_v3_v3v3(d2[1], d[2], d[3]);
- mul_v3_fl(d2[0], 1 - vrat);
+ mul_v3_fl(d2[0], 1.0f - vrat);
mul_v3_fl(d2[1], vrat);
add_v3_v3v3(out, d2[0], d2[1]);
diff --git a/source/blender/blenkernel/intern/multires_reshape_smooth.c b/source/blender/blenkernel/intern/multires_reshape_smooth.c
index f10aae18142..d7ab6773991 100644
--- a/source/blender/blenkernel/intern/multires_reshape_smooth.c
+++ b/source/blender/blenkernel/intern/multires_reshape_smooth.c
@@ -48,6 +48,39 @@
#include "atomic_ops.h"
#include "subdiv_converter.h"
+
+bool debug_invert_m3_m3(float m1[3][3], const float m2[3][3], const char *func, int line)
+{
+ float det;
+ int a, b;
+ bool success;
+
+ /* calc adjoint */
+ adjoint_m3_m3(m1, m2);
+
+ /* then determinant old matrix! */
+ det = determinant_m3_array(m2);
+
+ if (det > -0.0001 && det < 0.0001) {
+ fprintf(stderr, "matrix inverse error %s:%i\n\n", func, line);
+ }
+
+ success = (det != 0.0f);
+
+ if (LIKELY(det != 0.0f)) {
+ det = 1.0f / det;
+ for (a = 0; a < 3; a++) {
+ for (b = 0; b < 3; b++) {
+ m1[a][b] *= det;
+ }
+ }
+ }
+
+ return success;
+}
+
+//#define invert_m3_m3(m1, m2) debug_invert_m3_m3(m1, m2, __func__, __LINE__)
+
/* -------------------------------------------------------------------- */
/** \name Local Structs
* \{ */
diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.c b/source/blender/blenkernel/intern/multires_unsubdivide.c
index 02b9bb852d6..7440700a3de 100644
--- a/source/blender/blenkernel/intern/multires_unsubdivide.c
+++ b/source/blender/blenkernel/intern/multires_unsubdivide.c
@@ -881,7 +881,8 @@ static BMesh *get_bmesh_from_mesh(Mesh *mesh)
.use_toolflags = true,
}));
- BM_mesh_bm_from_me(bm,
+ BM_mesh_bm_from_me(NULL,
+ bm,
mesh,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
@@ -1151,6 +1152,7 @@ bool multires_unsubdivide_to_basemesh(MultiresUnsubdivideContext *context)
/* Store the new base-mesh as a mesh in context, free bmesh. */
context->base_mesh = BKE_mesh_new_nomain(0, 0, 0, 0, 0);
BM_mesh_bm_to_me(NULL,
+ NULL,
bm_base_mesh,
context->base_mesh,
(&(struct BMeshToMeshParams){
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 08c5beedbf3..a374c3252b9 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -1386,6 +1386,7 @@ static void sculptsession_bm_to_me_update_data_only(Object *ob, bool reorder)
BM_log_mesh_elems_reorder(ss->bm, ss->bm_log);
}
BM_mesh_bm_to_me(NULL,
+ NULL,
ss->bm,
ob->data,
(&(struct BMeshToMeshParams){
@@ -1795,6 +1796,7 @@ void BKE_sculpt_update_object_after_eval(Depsgraph *depsgraph, Object *ob_eval)
BLI_assert(me_eval != NULL);
sculpt_update_object(depsgraph, ob_orig, me_eval, false, false, false);
+ SCULPT_dynamic_topology_sync_layers(ob_orig, me_eval);
}
void BKE_sculpt_color_layer_create_if_needed(struct Object *object)
@@ -1811,17 +1813,19 @@ void BKE_sculpt_color_layer_create_if_needed(struct Object *object)
CustomData_add_layer(&orig_me->vdata, CD_PROP_COLOR, CD_DEFAULT, NULL, orig_me->totvert);
BKE_mesh_update_customdata_pointers(orig_me, true);
DEG_id_tag_update(&orig_me->id, ID_RECALC_GEOMETRY);
+ SCULPT_dynamic_topology_sync_layers(object, orig_me);
}
-/** \warning Expects a fully evaluated depsgraph. */
void BKE_sculpt_update_object_for_edit(
Depsgraph *depsgraph, Object *ob_orig, bool need_pmap, bool need_mask, bool need_colors)
{
- BLI_assert(ob_orig == DEG_get_original_object(ob_orig));
-
+ /* Update from sculpt operators and undo, to update sculpt session
+ * and PBVH after edits. */
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob_orig);
- Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval);
- BLI_assert(me_eval != NULL);
+ Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH);
+
+ BLI_assert(ob_orig == DEG_get_original_object(ob_orig));
sculpt_update_object(depsgraph, ob_orig, me_eval, need_pmap, need_mask, need_colors);
}
@@ -2101,9 +2105,13 @@ static PBVH *build_pbvh_for_dynamic_topology(Object *ob)
ob->sculpt->bm_smooth_shading,
ob->sculpt->bm_log,
ob->sculpt->cd_vert_node_offset,
- ob->sculpt->cd_face_node_offset);
+ ob->sculpt->cd_face_node_offset,
+ ob->sculpt->cd_origco_offset,
+ ob->sculpt->cd_origno_offset,
+ ob->sculpt->cd_origvcol_offset);
pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
pbvh_show_face_sets_set(pbvh, false);
+
return pbvh;
}
@@ -2168,12 +2176,17 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect
return pbvh;
}
+// XXX hack
+extern SCULPT_dynamic_topology_sync_layers(Object *ob, Mesh *me);
+
PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
{
if (ob == NULL || ob->sculpt == NULL) {
return NULL;
}
+ Scene *scene = DEG_get_input_scene(depsgraph);
+
bool respect_hide = true;
if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) {
if (!(BKE_paint_select_vert_test(ob) || BKE_paint_select_face_test(ob))) {
@@ -2183,6 +2196,8 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
PBVH *pbvh = ob->sculpt->pbvh;
if (pbvh != NULL) {
+ SCULPT_update_flat_vcol_shading(ob, scene);
+
/* NOTE: It is possible that grids were re-allocated due to modifier
* stack. Need to update those pointers. */
if (BKE_pbvh_type(pbvh) == PBVH_GRIDS) {
@@ -2193,6 +2208,11 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
BKE_sculpt_bvh_update_from_ccg(pbvh, subdiv_ccg);
}
}
+ else if (BKE_pbvh_type(pbvh) == PBVH_BMESH) {
+ Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
+
+ SCULPT_dynamic_topology_sync_layers(ob, BKE_object_get_original_mesh(ob));
+ }
return pbvh;
}
@@ -2213,6 +2233,11 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
}
ob->sculpt->pbvh = pbvh;
+
+ if (pbvh) {
+ SCULPT_update_flat_vcol_shading(ob, scene);
+ }
+
return pbvh;
}
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 8a98780d918..9cd1c87a518 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -49,7 +49,7 @@
#include <limits.h>
-#define LEAF_LIMIT 10000
+#define LEAF_LIMIT 4000
//#define PERFCNTRS
@@ -693,14 +693,18 @@ void BKE_pbvh_free(PBVH *pbvh)
MEM_freeN((void *)node->face_vert_indices);
}
if (node->bm_faces) {
- BLI_gset_free(node->bm_faces, NULL);
+ BLI_table_gset_free(node->bm_faces, NULL);
}
if (node->bm_unique_verts) {
- BLI_gset_free(node->bm_unique_verts, NULL);
+ BLI_table_gset_free(node->bm_unique_verts, NULL);
}
if (node->bm_other_verts) {
- BLI_gset_free(node->bm_other_verts, NULL);
+ BLI_table_gset_free(node->bm_other_verts, NULL);
}
+
+#ifdef PROXY_ADVANCED
+ BKE_pbvh_free_proxyarray(pbvh, node);
+#endif
}
}
@@ -1015,6 +1019,7 @@ typedef struct PBVHUpdateData {
float (*vnors)[3];
int flag;
bool show_sculpt_face_sets;
+ bool flat_vcol_shading;
} PBVHUpdateData;
static void pbvh_update_normals_accum_task_cb(void *__restrict userdata,
@@ -1296,6 +1301,7 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
}
if (node->flag & PBVH_UpdateDrawBuffers) {
+
const int update_flags = pbvh_get_buffers_update_flags(pbvh);
switch (pbvh->type) {
case PBVH_GRIDS:
@@ -1328,12 +1334,33 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
node->bm_faces,
node->bm_unique_verts,
node->bm_other_verts,
- update_flags);
+ update_flags,
+ pbvh->cd_vert_node_offset,
+ pbvh->face_sets_color_seed,
+ pbvh->face_sets_color_default,
+ data->flat_vcol_shading);
break;
}
}
}
+void BKE_pbvh_set_flat_vcol_shading(PBVH *pbvh, bool value)
+{
+ if (value != pbvh->flat_vcol_shading) {
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *node = pbvh->nodes + i;
+
+ if (!(node->flag & PBVH_Leaf)) {
+ continue;
+ }
+
+ BKE_pbvh_node_mark_rebuild_draw(node);
+ }
+ }
+
+ pbvh->flat_vcol_shading = value;
+}
+
static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode, int update_flag)
{
if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(pbvh->type, PBVH_GRIDS, PBVH_BMESH)) {
@@ -1356,11 +1383,28 @@ static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode,
}
}
+ CustomData *vdata;
+ CustomData *ldata;
+
+ if (pbvh->type == PBVH_BMESH) {
+ if (pbvh->bm) {
+ vdata = &pbvh->bm->vdata;
+ ldata = &pbvh->bm->ldata;
+ }
+ else {
+ vdata = ldata = NULL;
+ }
+ }
+ else {
+ vdata = pbvh->vdata;
+ ldata = pbvh->ldata;
+ }
+
+ GPU_pbvh_update_attribute_names(vdata, ldata);
+
/* Parallel creation and update of draw buffers. */
PBVHUpdateData data = {
- .pbvh = pbvh,
- .nodes = nodes,
- };
+ .pbvh = pbvh, .nodes = nodes, .flat_vcol_shading = pbvh->flat_vcol_shading};
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
@@ -1410,6 +1454,49 @@ static int pbvh_flush_bb(PBVH *pbvh, PBVHNode *node, int flag)
return update;
}
+void BKE_pbvh_update_origcolor_bmesh(PBVH *pbvh, PBVHNode *node)
+{
+ PBVHVertexIter vd;
+
+ if (!pbvh->bm || pbvh->cd_origvcol_offset < 0) {
+ return;
+ }
+
+ int cd_vcol_offset = CustomData_get_offset(&pbvh->bm->vdata, CD_PROP_COLOR);
+
+ if (cd_vcol_offset == -1) {
+ return;
+ }
+
+ BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_ALL)
+ {
+ float *c1 = BM_ELEM_CD_GET_VOID_P(vd.bm_vert, pbvh->cd_origvcol_offset);
+ float *c2 = BM_ELEM_CD_GET_VOID_P(vd.bm_vert, cd_vcol_offset);
+
+ copy_v4_v4(c1, c2);
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void BKE_pbvh_update_origco_bmesh(PBVH *pbvh, PBVHNode *node)
+{
+ PBVHVertexIter vd;
+
+ if (!pbvh->bm || pbvh->cd_origco_offset < 0 || pbvh->cd_origno_offset < 0) {
+ return;
+ }
+
+ BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_ALL)
+ {
+ float *no = BM_ELEM_CD_GET_VOID_P(vd.bm_vert, pbvh->cd_origno_offset);
+ float *co = BM_ELEM_CD_GET_VOID_P(vd.bm_vert, pbvh->cd_origco_offset);
+
+ copy_v3_v3(co, vd.bm_vert->co);
+ copy_v3_v3(no, vd.bm_vert->no);
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
void BKE_pbvh_update_bounds(PBVH *pbvh, int flag)
{
if (!pbvh->nodes) {
@@ -1512,28 +1599,28 @@ static void pbvh_grids_node_visibility_update(PBVH *pbvh, PBVHNode *node)
static void pbvh_bmesh_node_visibility_update(PBVHNode *node)
{
- GSet *unique, *other;
+ TableGSet *unique, *other;
unique = BKE_pbvh_bmesh_node_unique_verts(node);
other = BKE_pbvh_bmesh_node_other_verts(node);
- GSetIterator gs_iter;
+ BMVert *v;
- GSET_ITER (gs_iter, unique) {
- BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
+ TGSET_ITER (v, unique) {
if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
BKE_pbvh_node_fully_hidden_set(node, false);
return;
}
}
+ TGSET_ITER_END
- GSET_ITER (gs_iter, other) {
- BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
+ TGSET_ITER (v, other) {
if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
BKE_pbvh_node_fully_hidden_set(node, false);
return;
}
}
+ TGSET_ITER_END
BKE_pbvh_node_fully_hidden_set(node, true);
}
@@ -1857,9 +1944,22 @@ void BKE_pbvh_node_num_verts(PBVH *pbvh, PBVHNode *node, int *r_uniquevert, int
}
break;
case PBVH_BMESH:
- tot = BLI_gset_len(node->bm_unique_verts);
+ // not a leaf? return zero
+ if (!(node->flag & PBVH_Leaf)) {
+ if (r_totvert) {
+ *r_totvert = 0;
+ }
+
+ if (r_uniquevert) {
+ *r_uniquevert = 0;
+ }
+
+ return;
+ }
+
+ tot = BLI_table_gset_len(node->bm_unique_verts);
if (r_totvert) {
- *r_totvert = tot + BLI_gset_len(node->bm_other_verts);
+ *r_totvert = tot + BLI_table_gset_len(node->bm_other_verts);
}
if (r_uniquevert) {
*r_uniquevert = tot;
@@ -2139,8 +2239,8 @@ static bool pbvh_faces_node_raycast(PBVH *pbvh,
const float ray_normal[3],
struct IsectRayPrecalc *isect_precalc,
float *depth,
- int *r_active_vertex_index,
- int *r_active_face_index,
+ SculptVertRef *r_active_vertex_index,
+ SculptFaceRef *r_active_face_index,
float *r_face_normal)
{
const MVert *vert = pbvh->verts;
@@ -2189,8 +2289,8 @@ static bool pbvh_faces_node_raycast(PBVH *pbvh,
if (j == 0 ||
len_squared_v3v3(location, co[j]) < len_squared_v3v3(location, nearest_vertex_co)) {
copy_v3_v3(nearest_vertex_co, co[j]);
- *r_active_vertex_index = mloop[lt->tri[j]].v;
- *r_active_face_index = lt->poly;
+ *r_active_vertex_index = BKE_pbvh_make_vref(mloop[lt->tri[j]].v);
+ r_active_face_index->i = lt->poly;
}
}
}
@@ -2207,8 +2307,8 @@ static bool pbvh_grids_node_raycast(PBVH *pbvh,
const float ray_normal[3],
struct IsectRayPrecalc *isect_precalc,
float *depth,
- int *r_active_vertex_index,
- int *r_active_grid_index,
+ SculptVertRef *r_active_vertex_index,
+ SculptFaceRef *r_active_grid_index,
float *r_face_normal)
{
const int totgrid = node->totprim;
@@ -2274,13 +2374,14 @@ static bool pbvh_grids_node_raycast(PBVH *pbvh,
len_squared_v3v3(location, nearest_vertex_co)) {
copy_v3_v3(nearest_vertex_co, co[j]);
- *r_active_vertex_index = gridkey->grid_area * grid_index +
- (y + y_it[j]) * gridkey->grid_size + (x + x_it[j]);
+ *r_active_vertex_index = BKE_pbvh_make_vref(gridkey->grid_area * grid_index +
+ (y + y_it[j]) * gridkey->grid_size +
+ (x + x_it[j]));
}
}
}
if (r_active_grid_index) {
- *r_active_grid_index = grid_index;
+ r_active_grid_index->i = grid_index;
}
}
}
@@ -2302,8 +2403,8 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh,
const float ray_normal[3],
struct IsectRayPrecalc *isect_precalc,
float *depth,
- int *active_vertex_index,
- int *active_face_grid_index,
+ SculptVertRef *active_vertex_index,
+ SculptFaceRef *active_face_grid_index,
float *face_normal)
{
bool hit = false;
@@ -2338,7 +2439,7 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh,
face_normal);
break;
case PBVH_BMESH:
- BM_mesh_elem_index_ensure(pbvh->bm, BM_VERT);
+ // BM_mesh_elem_index_ensure(pbvh->bm, BM_VERT);
hit = pbvh_bmesh_node_raycast(node,
ray_start,
ray_normal,
@@ -2346,6 +2447,7 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh,
depth,
use_origco,
active_vertex_index,
+ active_face_grid_index,
face_normal);
break;
}
@@ -2913,9 +3015,23 @@ void BKE_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***r_array, int *r_tot)
PBVHColorBufferNode *BKE_pbvh_node_color_buffer_get(PBVHNode *node)
{
+ unsigned int totvert;
+
+ if (node->bm_unique_verts) {
+ totvert = BLI_table_gset_len(node->bm_unique_verts);
+ }
+ else {
+ totvert = node->uniq_verts;
+ }
+
+ if (node->color_buffer.color && node->color_buffer.size != totvert) {
+ MEM_freeN(node->color_buffer.color);
+ node->color_buffer.color = NULL;
+ }
if (!node->color_buffer.color) {
- node->color_buffer.color = MEM_callocN(sizeof(float[4]) * node->uniq_verts, "Color buffer");
+ node->color_buffer.color = MEM_callocN(sizeof(float[4]) * totvert, "Color buffer");
+ node->color_buffer.size = totvert;
}
return &node->color_buffer;
}
@@ -2941,8 +3057,11 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
vi->grid = NULL;
vi->no = NULL;
+ vi->col = NULL;
vi->fno = NULL;
vi->mvert = NULL;
+ vi->vertex.i = 0;
+ vi->index = 0;
vi->respect_hide = pbvh->respect_hide;
if (pbvh->respect_hide == false) {
@@ -2970,9 +3089,15 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
vi->mverts = verts;
if (pbvh->type == PBVH_BMESH) {
- BLI_gsetIterator_init(&vi->bm_unique_verts, node->bm_unique_verts);
- BLI_gsetIterator_init(&vi->bm_other_verts, node->bm_other_verts);
+ vi->bi = 0;
+ vi->bm_cur_set = node->bm_unique_verts;
+ vi->bm_unique_verts = node->bm_unique_verts;
+ vi->bm_other_verts = node->bm_other_verts;
vi->bm_vdata = &pbvh->bm->vdata;
+ vi->bm_vert = NULL;
+
+ // we ensure pbvh->cd_vcol_offset is up to date here too
+ vi->cd_vcol_offset = pbvh->cd_vcol_offset = CustomData_get_offset(vi->bm_vdata, CD_PROP_COLOR);
vi->cd_vert_mask_offset = CustomData_get_offset(vi->bm_vdata, CD_PAINT_MASK);
}
@@ -3002,6 +3127,15 @@ bool pbvh_has_mask(PBVH *pbvh)
return false;
}
+SculptVertRef BKE_pbvh_table_index_to_vertex(PBVH *pbvh, int idx)
+{
+ if (pbvh->type == PBVH_BMESH) {
+ SculptVertRef ref = {(intptr_t)pbvh->bm->vtable[idx]};
+ return ref;
+ }
+
+ return BKE_pbvh_make_vref(idx);
+}
bool pbvh_has_face_sets(PBVH *pbvh)
{
switch (pbvh->type) {
@@ -3010,7 +3144,7 @@ bool pbvh_has_face_sets(PBVH *pbvh)
case PBVH_FACES:
return (pbvh->pdata && CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS));
case PBVH_BMESH:
- return false;
+ return (pbvh->bm && CustomData_get_layer(&pbvh->bm->pdata, CD_SCULPT_FACE_SETS));
}
return false;
@@ -3070,3 +3204,462 @@ void BKE_pbvh_respect_hide_set(PBVH *pbvh, bool respect_hide)
{
pbvh->respect_hide = respect_hide;
}
+
+int BKE_pbvh_get_node_index(PBVH *pbvh, PBVHNode *node)
+{
+ return (int)(node - pbvh->nodes);
+}
+
+void BKE_pbvh_get_nodes(PBVH *pbvh, int flag, PBVHNode ***r_array, int *r_totnode)
+{
+ BKE_pbvh_search_gather(pbvh, update_search_cb, POINTER_FROM_INT(flag), r_array, r_totnode);
+}
+
+#ifdef PROXY_ADVANCED
+// TODO: if this really works, make sure to pull the neighbor iterator out of sculpt.c and put it
+// here
+/* clang-format off */
+# include "BKE_context.h"
+# include "DNA_object_types.h"
+# include "DNA_scene_types.h"
+# include "../../editors/sculpt_paint/sculpt_intern.h"
+/* clang-format on */
+
+int checkalloc(void **data, int esize, int oldsize, int newsize, int emask, int umask)
+{
+ // update channel if it already was allocated once, or is requested by umask
+ if (newsize != oldsize && (*data || (emask & umask))) {
+ if (*data) {
+ *data = MEM_reallocN(*data, newsize * esize);
+ }
+ else {
+ *data = MEM_mallocN(newsize * esize, "pbvh proxy vert arrays");
+ }
+ return emask;
+ }
+
+ return 0;
+}
+
+void BKE_pbvh_ensure_proxyarray_indexmap(PBVH *pbvh, PBVHNode *node, GHash *vert_node_map)
+{
+ ProxyVertArray *p = &node->proxyverts;
+
+ int totvert = 0;
+ BKE_pbvh_node_num_verts(pbvh, node, &totvert, NULL);
+
+ bool update = !p->indexmap || p->size != totvert;
+ update = update || (p->indexmap && BLI_ghash_len(p->indexmap) != totvert);
+
+ if (!update) {
+ return;
+ }
+
+ if (p->indexmap) {
+ BLI_ghash_free(p->indexmap, NULL, NULL);
+ }
+
+ GHash *gs = p->indexmap = BLI_ghash_ptr_new("BKE_pbvh_ensure_proxyarray_indexmap");
+
+ PBVHVertexIter vd;
+
+ int i = 0;
+ BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ BLI_ghash_insert(gs, (void *)vd.vertex.i, (void *)i);
+ i++;
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+bool pbvh_proxyarray_needs_update(PBVH *pbvh, PBVHNode *node, int mask)
+{
+ ProxyVertArray *p = &node->proxyverts;
+ int totvert = 0;
+
+ if (!(node->flag & PBVH_Leaf) || !node->bm_unique_verts) {
+ return false;
+ }
+
+ BKE_pbvh_node_num_verts(pbvh, node, &totvert, NULL);
+
+ bool bad = p->size != totvert;
+ bad = bad || ((mask & PV_NEIGHBORS) && p->neighbors_dirty);
+ bad = bad || (p->datamask & mask) != mask;
+
+ bad = bad && totvert > 0;
+
+ return bad;
+}
+
+GHash *pbvh_build_vert_node_map(PBVH *pbvh, PBVHNode **nodes, int totnode, int mask)
+{
+ GHash *vert_node_map = BLI_ghash_ptr_new("BKE_pbvh_ensure_proxyarrays");
+
+ for (int i = 0; i < totnode; i++) {
+ PBVHVertexIter vd;
+ PBVHNode *node = nodes[i];
+
+ if (!(node->flag & PBVH_Leaf)) {
+ continue;
+ }
+
+ BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ BLI_ghash_insert(vert_node_map, (void *)vd.vertex.i, (void *)(node - pbvh->nodes));
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+
+ return vert_node_map;
+}
+
+void BKE_pbvh_ensure_proxyarrays(
+ SculptSession *ss, PBVH *pbvh, PBVHNode **nodes, int totnode, int mask)
+{
+
+ bool update = false;
+
+ for (int i = 0; i < totnode; i++) {
+ if (pbvh_proxyarray_needs_update(pbvh, nodes[i], mask)) {
+ update = true;
+ break;
+ }
+ }
+
+ if (!update) {
+ return;
+ }
+
+ GHash *vert_node_map = pbvh_build_vert_node_map(pbvh, nodes, totnode, mask);
+
+ for (int i = 0; i < totnode; i++) {
+ if (nodes[i]->flag & PBVH_Leaf) {
+ BKE_pbvh_ensure_proxyarray_indexmap(pbvh, nodes[i], vert_node_map);
+ }
+ }
+
+ for (int i = 0; i < totnode; i++) {
+ if (nodes[i]->flag & PBVH_Leaf) {
+ BKE_pbvh_ensure_proxyarray(ss, pbvh, nodes[i], mask, vert_node_map, false, false);
+ }
+ }
+
+ if (vert_node_map) {
+ BLI_ghash_free(vert_node_map, NULL, NULL);
+ }
+}
+
+void BKE_pbvh_ensure_proxyarray(SculptSession *ss,
+ PBVH *pbvh,
+ PBVHNode *node,
+ int mask,
+ GHash *vert_node_map,
+ bool check_indexmap,
+ bool force_update)
+{
+ ProxyVertArray *p = &node->proxyverts;
+
+ if (check_indexmap) {
+ BKE_pbvh_ensure_proxyarray_indexmap(pbvh, node, vert_node_map);
+ }
+
+ GHash *gs = p->indexmap;
+
+ int totvert = 0;
+ BKE_pbvh_node_num_verts(pbvh, node, &totvert, NULL);
+
+ if (!totvert) {
+ return;
+ }
+
+ int updatemask = 0;
+
+# define UPDATETEST(name, emask, esize) \
+ if (mask & emask) { \
+ updatemask |= checkalloc((void **)&p->name, esize, p->size, totvert, emask, mask); \
+ }
+
+ UPDATETEST(ownerco, PV_OWNERCO, sizeof(void *))
+ UPDATETEST(ownerno, PV_OWNERNO, sizeof(void *))
+ UPDATETEST(ownermask, PV_OWNERMASK, sizeof(void *))
+ UPDATETEST(ownercolor, PV_OWNERCOLOR, sizeof(void *))
+ UPDATETEST(co, PV_CO, sizeof(float) * 3)
+ UPDATETEST(no, PV_NO, sizeof(short) * 3)
+ UPDATETEST(fno, PV_NO, sizeof(float) * 3)
+ UPDATETEST(mask, PV_MASK, sizeof(float))
+ UPDATETEST(color, PV_COLOR, sizeof(float) * 4)
+ UPDATETEST(index, PV_INDEX, sizeof(SculptVertRef))
+ UPDATETEST(neighbors, PV_NEIGHBORS, sizeof(ProxyKey) * MAX_PROXY_NEIGHBORS)
+
+ p->size = totvert;
+
+ if (force_update) {
+ updatemask |= mask;
+ }
+
+ if ((mask & PV_NEIGHBORS) && p->neighbors_dirty) {
+ updatemask |= PV_NEIGHBORS;
+ }
+
+ if (!updatemask) {
+ return;
+ }
+
+ p->datamask |= mask;
+
+ PBVHVertexIter vd;
+
+ int i = 0;
+
+# if 1
+ BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ void **val;
+
+ if (!BLI_ghash_ensure_p(gs, (void *)vd.vertex.i, &val)) {
+ *val = (void *)i;
+ };
+ i++;
+ }
+ BKE_pbvh_vertex_iter_end;
+# endif
+
+ if (updatemask & PV_NEIGHBORS) {
+ p->neighbors_dirty = false;
+ }
+
+ i = 0;
+ BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ if (i >= p->size) {
+ printf("error!! %s\n", __func__);
+ break;
+ }
+
+ if (updatemask & PV_OWNERCO) {
+ p->ownerco[i] = vd.co;
+ }
+ if (updatemask & PV_INDEX) {
+ p->index[i] = vd.vertex;
+ }
+ if (updatemask & PV_OWNERNO) {
+ p->ownerno[i] = vd.no;
+ }
+ if (updatemask & PV_NO) {
+ if (vd.fno) {
+ if (p->fno) {
+ copy_v3_v3(p->fno[i], vd.fno);
+ }
+ normal_float_to_short_v3(p->no[i], vd.fno);
+ }
+ else if (vd.no) {
+ copy_v3_v3_short(p->no[i], vd.no);
+ if (p->fno) {
+ normal_short_to_float_v3(p->fno[i], vd.no);
+ }
+ }
+ else {
+ p->no[i][0] = p->no[i][1] = p->no[i][2] = 0;
+ if (p->fno) {
+ zero_v3(p->fno[i]);
+ }
+ }
+ }
+ if (updatemask & PV_CO) {
+ copy_v3_v3(p->co[i], vd.co);
+ }
+ if (updatemask & PV_OWNERMASK) {
+ p->ownermask[i] = vd.mask;
+ }
+ if (updatemask & PV_MASK) {
+ p->mask[i] = vd.mask ? *vd.mask : 0.0f;
+ }
+ if (updatemask & PV_COLOR) {
+ if (vd.vcol) {
+ copy_v4_v4(p->color[i], vd.vcol->color);
+ }
+ }
+
+ if (updatemask & PV_NEIGHBORS) {
+ int j = 0;
+ SculptVertexNeighborIter ni;
+
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
+ if (j >= MAX_PROXY_NEIGHBORS - 1) {
+ break;
+ }
+
+ ProxyKey key;
+
+ int *pindex = (int *)BLI_ghash_lookup_p(gs, (void *)ni.vertex.i);
+
+ if (!pindex) {
+ if (vert_node_map) {
+ int *nindex = (int *)BLI_ghash_lookup_p(vert_node_map, (void *)ni.vertex.i);
+
+ if (!nindex) {
+ p->neighbors_dirty = true;
+ continue;
+ }
+
+ PBVHNode *node2 = pbvh->nodes + *nindex;
+ if (node2->proxyverts.indexmap) {
+ pindex = (int *)BLI_ghash_lookup_p(node2->proxyverts.indexmap, (void *)ni.vertex.i);
+ }
+ else {
+ pindex = NULL;
+ }
+
+ if (!pindex) {
+ p->neighbors_dirty = true;
+ continue;
+ }
+
+ key.node = (int)(node2 - pbvh->nodes);
+ key.pindex = *pindex;
+ //*
+ if (node2->proxyverts.size != 0 &&
+ (key.pindex < 0 || key.pindex >= node2->proxyverts.size)) {
+ printf("error! %s\n", __func__);
+ fflush(stdout);
+ p->neighbors_dirty = true;
+ continue;
+ }
+ //*/
+ }
+ else {
+ p->neighbors_dirty = true;
+ continue;
+ }
+ }
+ else {
+ key.node = (int)(node - pbvh->nodes);
+ key.pindex = *pindex;
+ }
+
+ p->neighbors[i][j++] = key;
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ p->neighbors[i][j].node = -1;
+ }
+
+ i++;
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+typedef struct GatherProxyThread {
+ PBVHNode **nodes;
+ PBVH *pbvh;
+ int mask;
+} GatherProxyThread;
+
+static void pbvh_load_proxyarray_exec(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ GatherProxyThread *data = (GatherProxyThread *)userdata;
+ PBVHNode *node = data->nodes[n];
+ PBVHVertexIter vd;
+ ProxyVertArray *p = &node->proxyverts;
+ int i = 0;
+
+ int mask = p->datamask;
+
+ BKE_pbvh_ensure_proxyarray(NULL, data->pbvh, node, data->mask, NULL, false, true);
+}
+
+void BKE_pbvh_load_proxyarrays(PBVH *pbvh, PBVHNode **nodes, int totnode, int mask)
+{
+ GatherProxyThread data = {.nodes = nodes, .pbvh = pbvh, .mask = mask};
+
+ mask = mask & ~PV_NEIGHBORS; // don't update neighbors in threaded code?
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, pbvh_load_proxyarray_exec, &settings);
+}
+
+static void pbvh_gather_proxyarray_exec(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ GatherProxyThread *data = (GatherProxyThread *)userdata;
+ PBVHNode *node = data->nodes[n];
+ PBVHVertexIter vd;
+ ProxyVertArray *p = &node->proxyverts;
+ int i = 0;
+
+ int mask = p->datamask;
+
+ BKE_pbvh_vertex_iter_begin(data->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ if (mask & PV_CO) {
+ copy_v3_v3(vd.co, p->co[i]);
+ }
+
+ if (mask & PV_COLOR && vd.col) {
+ copy_v4_v4(vd.col, p->color[i]);
+ }
+
+ if (vd.mask && (mask & PV_MASK)) {
+ *vd.mask = p->mask[i];
+ }
+
+ i++;
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void BKE_pbvh_gather_proxyarray(PBVH *pbvh, PBVHNode **nodes, int totnode)
+{
+ GatherProxyThread data = {.nodes = nodes, .pbvh = pbvh};
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, pbvh_gather_proxyarray_exec, &settings);
+}
+
+void BKE_pbvh_free_proxyarray(PBVH *pbvh, PBVHNode *node)
+{
+ ProxyVertArray *p = &node->proxyverts;
+
+ if (p->indexmap) {
+ BLI_ghash_free(p->indexmap, NULL, NULL);
+ }
+ if (p->co)
+ MEM_freeN(p->co);
+ if (p->no)
+ MEM_freeN(p->no);
+ if (p->index)
+ MEM_freeN(p->index);
+ if (p->mask)
+ MEM_freeN(p->mask);
+ if (p->ownerco)
+ MEM_freeN(p->ownerco);
+ if (p->ownerno)
+ MEM_freeN(p->ownerno);
+ if (p->ownermask)
+ MEM_freeN(p->ownermask);
+ if (p->ownercolor)
+ MEM_freeN(p->ownercolor);
+ if (p->color)
+ MEM_freeN(p->color);
+ if (p->neighbors)
+ MEM_freeN(p->neighbors);
+
+ memset(p, 0, sizeof(*p));
+}
+
+void BKE_pbvh_update_proxyvert(PBVH *pbvh, PBVHNode *node, ProxyVertUpdateRec *rec)
+{
+}
+
+ProxyVertArray *BKE_pbvh_get_proxyarrays(PBVH *pbvh, PBVHNode *node)
+{
+ return &node->proxyverts;
+}
+
+#endif
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 09e4ad93baa..27549dcb1ad 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -18,14 +18,38 @@
* \ingroup bli
*/
+ /*
+ TODO:
+
+ Convergence improvements:
+ 1. DONE: Limit number of edges processed per run.
+ 2. Scale split steps by ratio of long to short edges to
+ prevent runaway tesselation.
+ 3. Detect and dissolve three and four valence vertices that are surrounded by
+ all tris.
+ 4. Use different (coarser) brush spacing for applying dyntopo
+
+ Drawing improvements:
+ 4. Build and cache vertex index buffers, to reduce GPU bandwidth
+
+ Topology rake:
+ 5. Enable new curvature topology rake code and add to UI.
+ 6. Add code to cache curvature data per vertex in a CD layer.
+
+*/
+
#include "MEM_guardedalloc.h"
+#include "BLI_array.h"
#include "BLI_buffer.h"
#include "BLI_ghash.h"
#include "BLI_heap_simple.h"
#include "BLI_math.h"
#include "BLI_memarena.h"
+#include "BLI_rand.h"
+#include "BLI_task.h"
#include "BLI_utildefines.h"
+#include "PIL_time.h"
#include "BKE_DerivedMesh.h"
#include "BKE_ccg.h"
@@ -36,17 +60,49 @@
#include "bmesh.h"
#include "pbvh_intern.h"
+//#define DYNTOPO_TIME_LIMIT 0.015
+#define DYNTOPO_RUN_INTERVAL 0.02
+#define DYNTOPO_MAX_ITER 1024
+
+#define DYNTOPO_USE_HEAP
+
+#ifndef DYNTOPO_USE_HEAP
+/* don't add edges into the queue multiple times */
+# define USE_EDGEQUEUE_TAG
+#endif
+
/* Avoid skinny faces */
#define USE_EDGEQUEUE_EVEN_SUBDIV
+
#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
# include "BKE_global.h"
#endif
+#ifndef DEBUG
+# define DEBUG_DEFINED
+# define DEBUG
+#endif
+
+#ifdef WIN32
+# include "crtdbg.h"
+#endif
+
+static void check_heap()
+{
+#ifdef WIN32
+ if (!_CrtCheckMemory()) {
+ printf("Memory corruption!");
+ _CrtDbgBreak();
+ }
+# ifdef DEBUG_DEFINED
+# undef DEBUG_DEFINED
+# undef DEBUG
+# endif
+#endif
+}
/* Support for only operating on front-faces */
#define USE_EDGEQUEUE_FRONTFACE
-/* don't add edges into the queue multiple times */
-#define USE_EDGEQUEUE_TAG
/**
* Ensure we don't have dirty tags for the edge queue, and that they are left cleared.
* (slow, even for debug mode, so leave disabled for now).
@@ -201,21 +257,20 @@ static BMVert *bm_vert_hash_lookup_chain(GHash *deleted_verts, BMVert *v)
static void pbvh_bmesh_node_finalize(PBVH *pbvh,
const int node_index,
const int cd_vert_node_offset,
- const int cd_face_node_offset)
+ const int cd_face_node_offset,
+ bool add_orco)
{
- GSetIterator gs_iter;
PBVHNode *n = &pbvh->nodes[node_index];
bool has_visible = false;
/* Create vert hash sets */
- n->bm_unique_verts = BLI_gset_ptr_new("bm_unique_verts");
- n->bm_other_verts = BLI_gset_ptr_new("bm_other_verts");
+ n->bm_unique_verts = BLI_table_gset_new("bm_unique_verts");
+ n->bm_other_verts = BLI_table_gset_new("bm_other_verts");
BB_reset(&n->vb);
+ BMFace *f;
- GSET_ITER (gs_iter, n->bm_faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
-
+ TGSET_ITER (f, n->bm_faces) {
/* Update ownership of faces */
BM_ELEM_CD_SET_INT(f, cd_face_node_offset, node_index);
@@ -225,12 +280,12 @@ static void pbvh_bmesh_node_finalize(PBVH *pbvh,
do {
BMVert *v = l_iter->v;
- if (!BLI_gset_haskey(n->bm_unique_verts, v)) {
+ if (!BLI_table_gset_haskey(n->bm_unique_verts, v)) {
if (BM_ELEM_CD_GET_INT(v, cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
- BLI_gset_add(n->bm_other_verts, v);
+ BLI_table_gset_add(n->bm_other_verts, v);
}
else {
- BLI_gset_insert(n->bm_unique_verts, v);
+ BLI_table_gset_insert(n->bm_unique_verts, v);
BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, node_index);
}
}
@@ -242,6 +297,7 @@ static void pbvh_bmesh_node_finalize(PBVH *pbvh,
has_visible = true;
}
}
+ TGSET_ITER_END
BLI_assert(n->vb.bmin[0] <= n->vb.bmax[0] && n->vb.bmin[1] <= n->vb.bmax[1] &&
n->vb.bmin[2] <= n->vb.bmax[2]);
@@ -252,37 +308,51 @@ static void pbvh_bmesh_node_finalize(PBVH *pbvh,
BKE_pbvh_node_mark_rebuild_draw(n);
BKE_pbvh_node_fully_hidden_set(n, !has_visible);
- n->flag |= PBVH_UpdateNormals;
+ n->flag |= PBVH_UpdateNormals | PBVH_UpdateTopology;
+
+ if (add_orco) {
+ BKE_pbvh_bmesh_node_save_ortri(pbvh->bm, n);
+ }
}
/* Recursively split the node if it exceeds the leaf_limit */
-static void pbvh_bmesh_node_split(PBVH *pbvh, const BBC *bbc_array, int node_index)
+static void pbvh_bmesh_node_split(
+ PBVH *pbvh, const BBC *bbc_array, int node_index, bool add_orco, int depth)
{
const int cd_vert_node_offset = pbvh->cd_vert_node_offset;
const int cd_face_node_offset = pbvh->cd_face_node_offset;
PBVHNode *n = &pbvh->nodes[node_index];
- if (BLI_gset_len(n->bm_faces) <= pbvh->leaf_limit) {
+#ifdef PROXY_ADVANCED
+ BKE_pbvh_free_proxyarray(pbvh, n);
+#endif
+
+ if (depth > 6 || BLI_table_gset_len(n->bm_faces) <= pbvh->leaf_limit) {
/* Node limit not exceeded */
- pbvh_bmesh_node_finalize(pbvh, node_index, cd_vert_node_offset, cd_face_node_offset);
+ pbvh_bmesh_node_finalize(pbvh, node_index, cd_vert_node_offset, cd_face_node_offset, add_orco);
return;
}
/* Calculate bounding box around primitive centroids */
BB cb;
BB_reset(&cb);
- GSetIterator gs_iter;
- GSET_ITER (gs_iter, n->bm_faces) {
- const BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+ BMFace *f;
+
+ TGSET_ITER (f, n->bm_faces) {
const BBC *bbc = &bbc_array[BM_elem_index_get(f)];
BB_expand(&cb, bbc->bcentroid);
}
+ TGSET_ITER_END
/* Find widest axis and its midpoint */
const int axis = BB_widest_axis(&cb);
const float mid = (cb.bmax[axis] + cb.bmin[axis]) * 0.5f;
+ if (isnan(mid)) {
+ printf("NAN ERROR! %s\n", __func__);
+ }
+
/* Add two new child nodes */
const int children = pbvh->totnode;
n->children_offset = children;
@@ -293,63 +363,74 @@ static void pbvh_bmesh_node_split(PBVH *pbvh, const BBC *bbc_array, int node_ind
/* Initialize children */
PBVHNode *c1 = &pbvh->nodes[children], *c2 = &pbvh->nodes[children + 1];
+
c1->flag |= PBVH_Leaf;
c2->flag |= PBVH_Leaf;
- c1->bm_faces = BLI_gset_ptr_new_ex("bm_faces", BLI_gset_len(n->bm_faces) / 2);
- c2->bm_faces = BLI_gset_ptr_new_ex("bm_faces", BLI_gset_len(n->bm_faces) / 2);
+ c1->bm_faces = BLI_table_gset_new_ex("bm_faces", BLI_table_gset_len(n->bm_faces) / 2);
+ c2->bm_faces = BLI_table_gset_new_ex("bm_faces", BLI_table_gset_len(n->bm_faces) / 2);
+
+ c1->bm_unique_verts = c2->bm_unique_verts = NULL;
+ c1->bm_other_verts = c2->bm_other_verts = NULL;
/* Partition the parent node's faces between the two children */
- GSET_ITER (gs_iter, n->bm_faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+ TGSET_ITER (f, n->bm_faces) {
const BBC *bbc = &bbc_array[BM_elem_index_get(f)];
if (bbc->bcentroid[axis] < mid) {
- BLI_gset_insert(c1->bm_faces, f);
+ BLI_table_gset_insert(c1->bm_faces, f);
}
else {
- BLI_gset_insert(c2->bm_faces, f);
+ BLI_table_gset_insert(c2->bm_faces, f);
}
}
-
+ TGSET_ITER_END
+#if 0
/* Enforce at least one primitive in each node */
- GSet *empty = NULL, *other;
- if (BLI_gset_len(c1->bm_faces) == 0) {
+ TableGSet *empty = NULL, *other;
+ if (BLI_table_gset_len(c1->bm_faces) == 0) {
empty = c1->bm_faces;
other = c2->bm_faces;
}
- else if (BLI_gset_len(c2->bm_faces) == 0) {
+ else if (BLI_table_gset_len(c2->bm_faces) == 0) {
empty = c2->bm_faces;
other = c1->bm_faces;
}
+
if (empty) {
- GSET_ITER (gs_iter, other) {
- void *key = BLI_gsetIterator_getKey(&gs_iter);
- BLI_gset_insert(empty, key);
- BLI_gset_remove(other, key, NULL);
+ void *key;
+ TGSET_ITER (key, other) {
+ BLI_table_gset_insert(empty, key);
+ BLI_table_gset_remove(other, key, NULL);
break;
- }
+ } TGSET_ITER_END
}
-
+#endif
/* Clear this node */
+ BMVert *v;
+
/* Mark this node's unique verts as unclaimed */
if (n->bm_unique_verts) {
- GSET_ITER (gs_iter, n->bm_unique_verts) {
- BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
+ TGSET_ITER (v, n->bm_unique_verts) {
BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE);
}
- BLI_gset_free(n->bm_unique_verts, NULL);
+ TGSET_ITER_END
+
+ BLI_table_gset_free(n->bm_unique_verts, NULL);
}
- /* Unclaim faces */
- GSET_ITER (gs_iter, n->bm_faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
- BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE);
+ if (n->bm_faces) {
+ /* Unclaim faces */
+ TGSET_ITER (f, n->bm_faces) {
+ BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE);
+ }
+ TGSET_ITER_END
+
+ BLI_table_gset_free(n->bm_faces, NULL);
}
- BLI_gset_free(n->bm_faces, NULL);
if (n->bm_other_verts) {
- BLI_gset_free(n->bm_other_verts, NULL);
+ BLI_table_gset_free(n->bm_other_verts, NULL);
}
if (n->layer_disp) {
@@ -368,8 +449,8 @@ static void pbvh_bmesh_node_split(PBVH *pbvh, const BBC *bbc_array, int node_ind
n->flag &= ~PBVH_Leaf;
/* Recurse */
- pbvh_bmesh_node_split(pbvh, bbc_array, children);
- pbvh_bmesh_node_split(pbvh, bbc_array, children + 1);
+ pbvh_bmesh_node_split(pbvh, bbc_array, children, add_orco, depth + 1);
+ pbvh_bmesh_node_split(pbvh, bbc_array, children + 1, add_orco, depth + 1);
/* Array maybe reallocated, update current node pointer */
n = &pbvh->nodes[node_index];
@@ -381,11 +462,19 @@ static void pbvh_bmesh_node_split(PBVH *pbvh, const BBC *bbc_array, int node_ind
n->orig_vb = n->vb;
}
+static void pbvh_bmesh_copy_facedata(BMesh *bm, BMFace *dest, BMFace *src)
+{
+ dest->head.hflag = src->head.hflag;
+ dest->mat_nr = src->mat_nr;
+ CustomData_bmesh_copy_data(&bm->pdata, &bm->pdata, src->head.data, &dest->head.data);
+}
+
/* Recursively split the node if it exceeds the leaf_limit */
static bool pbvh_bmesh_node_limit_ensure(PBVH *pbvh, int node_index)
{
- GSet *bm_faces = pbvh->nodes[node_index].bm_faces;
- const int bm_faces_size = BLI_gset_len(bm_faces);
+ TableGSet *bm_faces = pbvh->nodes[node_index].bm_faces;
+ const int bm_faces_size = BLI_table_gset_len(bm_faces);
+
if (bm_faces_size <= pbvh->leaf_limit) {
/* Node limit not exceeded */
return false;
@@ -394,10 +483,20 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *pbvh, int node_index)
/* For each BMFace, store the AABB and AABB centroid */
BBC *bbc_array = MEM_mallocN(sizeof(BBC) * bm_faces_size, "BBC");
- GSetIterator gs_iter;
+ BMFace *f;
+
int i;
- GSET_ITER_INDEX (gs_iter, bm_faces, i) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+
+ /*
+ TGSET_ITER_INDEX(f, bm_faces, i)
+ {
+ }
+ TGSET_ITER_INDEX_END
+ printf("size: %d %d\n", i + 1, bm_faces_size);
+ */
+
+ TGSET_ITER_INDEX(f, bm_faces, i)
+ {
BBC *bbc = &bbc_array[i];
BB_reset((BB *)bbc);
@@ -411,10 +510,12 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *pbvh, int node_index)
/* so we can do direct lookups on 'bbc_array' */
BM_elem_index_set(f, i); /* set_dirty! */
}
+ TGSET_ITER_INDEX_END
+
/* Likely this is already dirty. */
pbvh->bm->elem_index_dirty |= BM_FACE;
- pbvh_bmesh_node_split(pbvh, bbc_array, node_index);
+ pbvh_bmesh_node_split(pbvh, bbc_array, node_index, pbvh->nodes[node_index].bm_ortri != NULL, 0);
MEM_freeN(bbc_array);
@@ -477,12 +578,18 @@ BLI_INLINE int pbvh_bmesh_node_index_from_face(PBVH *pbvh, const BMFace *key)
BLI_INLINE PBVHNode *pbvh_bmesh_node_from_vert(PBVH *pbvh, const BMVert *key)
{
- return &pbvh->nodes[pbvh_bmesh_node_index_from_vert(pbvh, key)];
+ int ni = pbvh_bmesh_node_index_from_vert(pbvh, key);
+
+ return ni >= 0 ? pbvh->nodes + ni : NULL;
+ // return &pbvh->nodes[pbvh_bmesh_node_index_from_vert(pbvh, key)];
}
BLI_INLINE PBVHNode *pbvh_bmesh_node_from_face(PBVH *pbvh, const BMFace *key)
{
- return &pbvh->nodes[pbvh_bmesh_node_index_from_face(pbvh, key)];
+ int ni = pbvh_bmesh_node_index_from_face(pbvh, key);
+
+ return ni >= 0 ? pbvh->nodes + ni : NULL;
+ // return &pbvh->nodes[pbvh_bmesh_node_index_from_face(pbvh, key)];
}
static BMVert *pbvh_bmesh_vert_create(PBVH *pbvh,
@@ -502,13 +609,14 @@ static BMVert *pbvh_bmesh_vert_create(PBVH *pbvh,
/* This value is logged below */
copy_v3_v3(v->no, no);
- BLI_gset_insert(node->bm_unique_verts, v);
+ BLI_table_gset_insert(node->bm_unique_verts, v);
BM_ELEM_CD_SET_INT(v, pbvh->cd_vert_node_offset, node_index);
node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
/* Log the new vertex */
BM_log_vert_added(pbvh->bm_log, v, cd_vert_mask_offset);
+ v->head.index = pbvh->bm->totvert; // set provisional index
return v;
}
@@ -527,7 +635,7 @@ static BMFace *pbvh_bmesh_face_create(
BMFace *f = BM_face_create(pbvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP);
f->head.hflag = f_example->head.hflag;
- BLI_gset_insert(node->bm_faces, f);
+ BLI_table_gset_insert(node->bm_faces, f);
BM_ELEM_CD_SET_INT(f, pbvh->cd_face_node_offset, node_index);
/* mark node for update */
@@ -606,18 +714,21 @@ static void pbvh_bmesh_vert_ownership_transfer(PBVH *pbvh, PBVHNode *new_owner,
{
PBVHNode *current_owner = pbvh_bmesh_node_from_vert(pbvh, v);
/* mark node for update */
- current_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
- BLI_assert(current_owner != new_owner);
+ if (current_owner) {
+ current_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
+
+ BLI_assert(current_owner != new_owner);
- /* Remove current ownership */
- BLI_gset_remove(current_owner->bm_unique_verts, v, NULL);
+ /* Remove current ownership */
+ BLI_table_gset_remove(current_owner->bm_unique_verts, v, NULL);
+ }
/* Set new ownership */
BM_ELEM_CD_SET_INT(v, pbvh->cd_vert_node_offset, new_owner - pbvh->nodes);
- BLI_gset_insert(new_owner->bm_unique_verts, v);
- BLI_gset_remove(new_owner->bm_other_verts, v, NULL);
- BLI_assert(!BLI_gset_haskey(new_owner->bm_other_verts, v));
+ BLI_table_gset_insert(new_owner->bm_unique_verts, v);
+ BLI_table_gset_remove(new_owner->bm_other_verts, v, NULL);
+ BLI_assert(!BLI_table_gset_haskey(new_owner->bm_other_verts, v));
/* mark node for update */
new_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
@@ -629,7 +740,7 @@ static void pbvh_bmesh_vert_remove(PBVH *pbvh, BMVert *v)
int f_node_index_prev = DYNTOPO_NODE_NONE;
PBVHNode *v_node = pbvh_bmesh_node_from_vert(pbvh, v);
- BLI_gset_remove(v_node->bm_unique_verts, v, NULL);
+ BLI_table_gset_remove(v_node->bm_unique_verts, v, NULL);
BM_ELEM_CD_SET_INT(v, pbvh->cd_vert_node_offset, DYNTOPO_NODE_NONE);
/* Have to check each neighboring face's node */
@@ -637,8 +748,12 @@ static void pbvh_bmesh_vert_remove(PBVH *pbvh, BMVert *v)
BM_FACES_OF_VERT_ITER_BEGIN (f, v) {
const int f_node_index = pbvh_bmesh_node_index_from_face(pbvh, f);
+ if (f_node_index == DYNTOPO_NODE_NONE) {
+ continue;
+ }
+
/* faces often share the same node,
- * quick check to avoid redundant #BLI_gset_remove calls */
+ * quick check to avoid redundant #BLI_table_gset_remove calls */
if (f_node_index_prev != f_node_index) {
f_node_index_prev = f_node_index;
@@ -646,10 +761,10 @@ static void pbvh_bmesh_vert_remove(PBVH *pbvh, BMVert *v)
f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
/* Remove current ownership */
- BLI_gset_remove(f_node->bm_other_verts, v, NULL);
+ BLI_table_gset_remove(f_node->bm_other_verts, v, NULL);
- BLI_assert(!BLI_gset_haskey(f_node->bm_unique_verts, v));
- BLI_assert(!BLI_gset_haskey(f_node->bm_other_verts, v));
+ BLI_assert(!BLI_table_gset_haskey(f_node->bm_unique_verts, v));
+ BLI_assert(!BLI_table_gset_haskey(f_node->bm_other_verts, v));
}
}
BM_FACES_OF_VERT_ITER_END;
@@ -659,6 +774,11 @@ static void pbvh_bmesh_face_remove(PBVH *pbvh, BMFace *f)
{
PBVHNode *f_node = pbvh_bmesh_node_from_face(pbvh, f);
+ if (!f_node) {
+ printf("pbvh corruption\n");
+ fflush(stdout);
+ return;
+ }
/* Check if any of this face's vertices need to be removed
* from the node */
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
@@ -666,7 +786,7 @@ static void pbvh_bmesh_face_remove(PBVH *pbvh, BMFace *f)
do {
BMVert *v = l_iter->v;
if (pbvh_bmesh_node_vert_use_count_is_equal(pbvh, f_node, v, 1)) {
- if (BLI_gset_haskey(f_node->bm_unique_verts, v)) {
+ if (BLI_table_gset_haskey(f_node->bm_unique_verts, v)) {
/* Find a different node that uses 'v' */
PBVHNode *new_node;
@@ -679,13 +799,13 @@ static void pbvh_bmesh_face_remove(PBVH *pbvh, BMFace *f)
}
else {
/* Remove from other verts */
- BLI_gset_remove(f_node->bm_other_verts, v, NULL);
+ BLI_table_gset_remove(f_node->bm_other_verts, v, NULL);
}
}
} while ((l_iter = l_iter->next) != l_first);
/* Remove face from node and top level */
- BLI_gset_remove(f_node->bm_faces, f, NULL);
+ BLI_table_gset_remove(f_node->bm_faces, f, NULL);
BM_ELEM_CD_SET_INT(f, pbvh->cd_face_node_offset, DYNTOPO_NODE_NONE);
/* Log removed face */
@@ -730,6 +850,10 @@ struct EdgeQueue;
typedef struct EdgeQueue {
HeapSimple *heap;
+
+ void **elems;
+ int totelems;
+
const float *center;
float center_proj[3]; /* for when we use projected coords. */
float radius_squared;
@@ -739,6 +863,7 @@ typedef struct EdgeQueue {
#endif
bool (*edge_queue_tri_in_range)(const struct EdgeQueue *q, BMFace *f);
+ bool (*edge_queue_vert_in_range)(const struct EdgeQueue *q, BMVert *v);
const float *view_normal;
#ifdef USE_EDGEQUEUE_FRONTFACE
@@ -755,6 +880,50 @@ typedef struct {
int cd_face_node_offset;
} EdgeQueueContext;
+BLI_INLINE float calc_weighted_edge_split(EdgeQueueContext *eq_ctx, BMVert *v1, BMVert *v2)
+{
+#if 0
+ float l = len_squared_v3v3(v1->co, v2->co);
+ float n;
+
+ n = (float)(BM_vert_edge_count(v1) + BM_vert_edge_count(v2)) * 0.5f;
+ n = MAX2(n - 6.0f, 1.0f);
+
+ return l * (n);
+#elif 1 // penalize 4-valence verts
+ float l = len_squared_v3v3(v1->co, v2->co);
+ if (BM_vert_edge_count(v1) == 4 || BM_vert_edge_count(v2) == 4) {
+ l *= 0.25f;
+ }
+
+ return l;
+#else
+ return len_squared_v3v3(v1->co, v2->co);
+#endif
+}
+
+BLI_INLINE float calc_weighted_edge_collapse(EdgeQueueContext *eq_ctx, BMVert *v1, BMVert *v2)
+{
+#if 0
+ float l = len_squared_v3v3(v1->co, v2->co);
+ float n;
+
+ n = (float)(BM_vert_edge_count(v1) + BM_vert_edge_count(v2)) * 0.5f;
+ n = MAX2(n - 5.0f, 1.0f);
+
+ return l * (n*n*4.0f);
+#elif 1 // penalize 4-valence verts
+ float l = len_squared_v3v3(v1->co, v2->co);
+ // if (BM_vert_edge_count(v1) == 4 || BM_vert_edge_count(v2) == 4) {
+ // l *= 0.25f;
+ //}
+
+ return l;
+#else
+ return len_squared_v3v3(v1->co, v2->co);
+#endif
+}
+
/* only tag'd edges are in the queue */
#ifdef USE_EDGEQUEUE_TAG
# define EDGE_QUEUE_TEST(e) (BM_elem_flag_test((CHECK_TYPE_INLINE(e, BMEdge *), e), BM_ELEM_TAG))
@@ -794,18 +963,215 @@ static void pbvh_bmesh_edge_tag_verify(PBVH *pbvh)
}
#endif
+static bool edge_queue_vert_in_sphere(const EdgeQueue *q, BMVert *v)
+{
+ /* Check if triangle intersects the sphere */
+ return len_squared_v3v3(q->center, v->co) <= q->radius_squared;
+}
+
+/* reduce script
+
+on factor;
+
+ax := 0;
+ay := 0;
+
+e1x := bx - ax;
+e1y := by - ay;
+e2x := cx - bx;
+e2y := cy - by;
+e3x := ax - cx;
+e3y := ay - cy;
+
+l1 := (e1x**2 + e1y**2)**0.5;
+l2 := (e2x**2 + e2y**2)**0.5;
+l3 := (e3x**2 + e3y**2)**0.5;
+
+load_package "avector";
+
+e1 := avec(e1x / l1, e1y / l1, 0.0);
+e2 := avec(e2x / l2, e2y / l2, 0.0);
+e3 := avec(e3x / l3, e3y / l3, 0.0);
+
+ax := 0;
+ay := 0;
+
+d1 := x1*e1[1] - y1*e1[0];
+d2 := x1*e2[1] - y1*e2[0];
+d3 := x1*e3[1] - y1*e3[0];
+
+d1 := d1**2;
+d2 := d2**2;
+d3 := d3**2;
+
+on fort;
+d1;
+d2;
+d3;
+off fort;
+
+fdis := (sqrt(dis)/nz)**2 + planedis**2;
+*/
+
+static float dist_to_tri_sphere(float p[3], float v1[3], float v2[3], float v3[3], float n[3])
+{
+
+ // find projection axis;
+ int axis1, axis2, axis3;
+ double nx = n[0] < 0.0 ? -n[0] : n[0];
+ double ny = n[1] < 0.0 ? -n[1] : n[1];
+ double nz = n[2] < 0.0 ? -n[2] : n[2];
+
+ const double feps = 0.000001;
+
+ if (nx > ny && nx > nz) {
+ axis1 = 1;
+ axis2 = 2;
+ axis3 = 0;
+ }
+ else if (ny > nx && ny > nz) {
+ axis1 = 0;
+ axis2 = 2;
+ axis3 = 1;
+ }
+ else {
+ axis1 = 0;
+ axis2 = 1;
+ axis3 = 2;
+ }
+
+ double planedis = (p[0] - v1[0]) * n[0] + (p[1] - v1[1]) * n[1] + (p[2] - v1[2]) * n[2];
+ planedis = planedis < 0.0 ? -planedis : planedis;
+
+ double ax = v1[axis1], ay = v1[axis2];
+ double bx = v2[axis1] - ax, by = v2[axis2] - ay;
+ double cx = v3[axis1] - ax, cy = v3[axis2] - ay;
+ double bx2 = bx * bx, by2 = by * by, cx2 = cx * cx, cy2 = cy * cy;
+
+ double x1 = p[axis1] - ax;
+ double y1 = p[axis2] - ay;
+
+ bool s1 = x1 * by - y1 * bx < 0.0;
+ bool s2 = x1 * (cy - by) - y1 * (cx - bx) < 0.0;
+ bool s3 = x1 * -cy - y1 * -cx < 0.0;
+
+ int side = 0;
+
+ int mask = s1 | (s2 << 1) | (s3 << 2);
+ if (mask == 0.0) {
+ return planedis * planedis;
+ }
+
+ double d1, d2, d3, div;
+
+ /*
+//\ 3|
+// \ |
+// b
+// | \
+// 1 | \ 2
+// | 0 \
+// ___a_______c___
+// 5 | 4 \ 6
+*/
+
+ double dis = 0.0;
+ switch (mask) {
+ case 1:
+ div = (bx2 + by2);
+
+ if (div > feps) {
+ d1 = (bx * y1 - by * x1);
+ d1 = (d1 * d1) / div;
+ }
+ else {
+ d1 = x1 * x1 + y1 * y1;
+ }
+
+ dis = d1;
+ break;
+ case 3:
+ dis = ((x1 - bx) * (x1 - bx) + (y1 - by) * (y1 - by));
+ break;
+ case 2:
+ div = ((bx - cx) * (bx - cx) + (by - cy) * (by - cy));
+ if (div > feps) {
+ d2 = ((bx - cx) * y1 - (by - cy) * x1);
+ d2 = (d2 * d2) / div;
+ }
+ else {
+ d2 = (x1 - bx) * (x1 - bx) + (y1 - by) * (y1 - by);
+ }
+ dis = d2;
+ break;
+ case 6:
+ dis = (x1 - cx) * (x1 - cx) + (y1 - cy) * (y1 - cy);
+ break;
+ case 4:
+ div = (cx2 + cy2);
+
+ if (div > feps) {
+ d3 = (cx * y1 - cy * x1);
+ d3 = (d3 * d3) / div;
+ }
+ else {
+ d3 = (x1 - cx) * (x1 - cx) + (y1 - cy) * (y1 - cy);
+ }
+
+ dis = d3;
+ break;
+ case 5:
+ dis = x1 * x1 + y1 * y1;
+ break;
+ }
+
+ nz = n[axis3] < 0.0 ? -n[axis3] : n[axis3];
+
+ return (float)(dis + nz * nz * planedis * planedis) / (nz * nz);
+}
+
static bool edge_queue_tri_in_sphere(const EdgeQueue *q, BMFace *f)
{
- BMVert *v_tri[3];
float c[3];
+ float v1[3], v2[3], v3[3], co[3];
+ const float mul = 1.0f;
+
+ BMLoop *l = f->l_first;
+
+ /* Check if triangle intersects the sphere */
+ float dis = dist_to_tri_sphere(q->center, l->v->co, l->next->v->co, l->prev->v->co, f->no);
+
+ // closest_on_tri_to_point_v3(c, co, v1, v2, v3);
+
+ // float dis2 = len_squared_v3v3(q->center, c);
+ // float dis3 = sqrtf(dis2);
+
+ return dis <= q->radius_squared;
/* Get closest point in triangle to sphere center */
- BM_face_as_array_vert_tri(f, v_tri);
+#if 0
+ /*
+ closest_on_tri_to_point_v3 is being slow
+ */
+
+ float mindis = 1e17;
+ float dis;
+ copy_v3_v3(c, q->center);
- closest_on_tri_to_point_v3(c, q->center, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co);
+ for (int i=0; i<3; i++) {
+ dis = len_squared_v3v3(v_tri[i]->co, c);
+ mindis = MIN2(mindis, dis);
+
+ dis = dist_squared_to_line_segment_v3(c, v_tri[i]->co, v_tri[(i+1)%3]->co);
+ mindis = MIN2(mindis, dis);
+ }
+ return mindis <= q->radius_squared;
+#else
+ closest_on_tri_to_point_v3(c, q->center, l->v->co, l->next->v->co, l->prev->v->co);
/* Check if triangle intersects the sphere */
return len_squared_v3v3(q->center, c) <= q->radius_squared;
+#endif
}
static bool edge_queue_tri_in_circle(const EdgeQueue *q, BMFace *f)
@@ -827,6 +1193,42 @@ static bool edge_queue_tri_in_circle(const EdgeQueue *q, BMFace *f)
return len_squared_v3v3(q->center_proj, c) <= q->radius_squared;
}
+typedef struct EdgeQueueThreadData {
+ PBVH *pbvh;
+ PBVHNode *node;
+ BMEdge **edges;
+ EdgeQueueContext *eq_ctx;
+ int totedge;
+ int size;
+} EdgeQueueThreadData;
+
+void edge_thread_data_insert(EdgeQueueThreadData *tdata, BMEdge *e)
+{
+ if (tdata->size <= tdata->totedge) {
+ tdata->size = (tdata->totedge + 1) << 1;
+ if (!tdata->edges) {
+ tdata->edges = MEM_mallocN(sizeof(void *) * tdata->size, "edge_thread_data_insert");
+ }
+ else {
+ tdata->edges = MEM_reallocN(tdata->edges, sizeof(void *) * tdata->size);
+ }
+ }
+
+ e->head.hflag |= BM_ELEM_TAG;
+
+ tdata->edges[tdata->totedge] = e;
+ tdata->totedge++;
+}
+
+static bool edge_queue_vert_in_circle(const EdgeQueue *q, BMVert *v)
+{
+ float c[3];
+
+ project_plane_normalized_v3_v3v3(c, v->co, q->view_normal);
+
+ return len_squared_v3v3(q->center_proj, c) <= q->radius_squared;
+}
+
/* Return true if the vertex mask is less than 1.0, false otherwise */
static bool check_mask(EdgeQueueContext *eq_ctx, BMVert *v)
{
@@ -835,6 +1237,10 @@ static bool check_mask(EdgeQueueContext *eq_ctx, BMVert *v)
static void edge_queue_insert(EdgeQueueContext *eq_ctx, BMEdge *e, float priority)
{
+ void **elems = eq_ctx->q->elems;
+ BLI_array_declare(elems);
+ BLI_array_len_set(elems, eq_ctx->q->totelems);
+
/* Don't let topology update affect fully masked vertices. This used to
* have a 50% mask cutoff, with the reasoning that you can't do a 50%
* topology update. But this gives an ugly border in the mesh. The mask
@@ -848,7 +1254,14 @@ static void edge_queue_insert(EdgeQueueContext *eq_ctx, BMEdge *e, float priorit
BMVert **pair = BLI_mempool_alloc(eq_ctx->pool);
pair[0] = e->v1;
pair[1] = e->v2;
+#ifdef DYNTOPO_USE_HEAP
BLI_heapsimple_insert(eq_ctx->q->heap, priority, pair);
+#endif
+
+ BLI_array_append(elems, pair);
+ eq_ctx->q->elems = elems;
+ eq_ctx->q->totelems = BLI_array_len(elems);
+
#ifdef USE_EDGEQUEUE_TAG
BLI_assert(EDGE_QUEUE_TEST(e) == false);
EDGE_QUEUE_ENABLE(e);
@@ -933,7 +1346,7 @@ static void short_edge_queue_edge_add(EdgeQueueContext *eq_ctx, BMEdge *e)
if (EDGE_QUEUE_TEST(e) == false)
#endif
{
- const float len_sq = BM_edge_calc_length_squared(e);
+ const float len_sq = calc_weighted_edge_collapse(eq_ctx, e->v1, e->v2);
if (len_sq < eq_ctx->q->limit_len_squared) {
edge_queue_insert(eq_ctx, e, len_sq);
}
@@ -990,6 +1403,166 @@ static void short_edge_queue_face_add(EdgeQueueContext *eq_ctx, BMFace *f)
}
}
+static void long_edge_queue_edge_add_recursive_2(
+ EdgeQueueThreadData *tdata, BMLoop *l_edge, BMLoop *l_end, const float len_sq, float limit_len)
+{
+ BLI_assert(len_sq > square_f(limit_len));
+
+ if (l_edge->e->head.hflag & BM_ELEM_TAG) {
+ return;
+ }
+
+#ifdef USE_EDGEQUEUE_FRONTFACE
+ if (tdata->eq_ctx->q->use_view_normal) {
+ if (dot_v3v3(l_edge->f->no, tdata->eq_ctx->q->view_normal) < 0.0f) {
+ return;
+ }
+ }
+#endif
+
+ edge_thread_data_insert(tdata, l_edge->e);
+
+ /* temp support previous behavior! */
+ if (UNLIKELY(G.debug_value == 1234)) {
+ return;
+ }
+
+ if ((l_edge->radial_next != l_edge)) {
+ /* How much longer we need to be to consider for subdividing
+ * (avoids subdividing faces which are only *slightly* skinny) */
+#define EVEN_EDGELEN_THRESHOLD 1.2f
+ /* How much the limit increases per recursion
+ * (avoids performing subdivisions too far away). */
+#define EVEN_GENERATION_SCALE 1.6f
+
+ const float len_sq_cmp = len_sq * EVEN_EDGELEN_THRESHOLD;
+
+ limit_len *= EVEN_GENERATION_SCALE;
+ const float limit_len_sq = square_f(limit_len);
+
+ BMLoop *l_iter = l_edge;
+ do {
+ BMLoop *l_adjacent[2] = {l_iter->next, l_iter->prev};
+ for (int i = 0; i < ARRAY_SIZE(l_adjacent); i++) {
+ float len_sq_other = calc_weighted_edge_split(
+ tdata->eq_ctx, l_adjacent[i]->e->v1, l_adjacent[i]->e->v2);
+ if (len_sq_other > max_ff(len_sq_cmp, limit_len_sq)) {
+ // edge_queue_insert(eq_ctx, l_adjacent[i]->e, -len_sq_other);
+ long_edge_queue_edge_add_recursive_2(
+ tdata, l_adjacent[i]->radial_next, l_adjacent[i], len_sq_other, limit_len);
+ }
+ }
+ } while ((l_iter = l_iter->radial_next) != l_end);
+
+#undef EVEN_EDGELEN_THRESHOLD
+#undef EVEN_GENERATION_SCALE
+ }
+}
+
+void long_edge_queue_task_cb(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ EdgeQueueThreadData *tdata = ((EdgeQueueThreadData *)userdata) + n;
+ PBVHNode *node = tdata->node;
+ EdgeQueueContext *eq_ctx = tdata->eq_ctx;
+
+ BMFace *f;
+
+ TGSET_ITER (f, node->bm_faces) {
+ BMLoop *l = f->l_first;
+
+ do {
+ l->e->head.hflag &= ~BM_ELEM_TAG;
+ l = l->next;
+ } while (l != f->l_first);
+ }
+ TGSET_ITER_END
+
+ TGSET_ITER (f, node->bm_faces) {
+#ifdef USE_EDGEQUEUE_FRONTFACE
+ if (eq_ctx->q->use_view_normal) {
+ if (dot_v3v3(f->no, eq_ctx->q->view_normal) < 0.0f) {
+ continue;
+ }
+ }
+#endif
+
+ if (eq_ctx->q->edge_queue_tri_in_range(eq_ctx->q, f)) {
+ /* Check each edge of the face */
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter = l_first;
+ do {
+#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
+ const float len_sq = BM_edge_calc_length_squared(l_iter->e);
+ if (len_sq > eq_ctx->q->limit_len_squared) {
+ long_edge_queue_edge_add_recursive_2(
+ tdata, l_iter->radial_next, l_iter, len_sq, eq_ctx->q->limit_len);
+ }
+#else
+ const float len_sq = BM_edge_calc_length_squared(l_iter->e);
+ if (len_sq > eq_ctx->q->limit_len_squared) {
+ edge_thread_data_insert(tdata, l_iter->e);
+ }
+#endif
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ }
+ TGSET_ITER_END
+}
+
+void short_edge_queue_task_cb(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ EdgeQueueThreadData *tdata = ((EdgeQueueThreadData *)userdata) + n;
+ PBVHNode *node = tdata->node;
+ EdgeQueueContext *eq_ctx = tdata->eq_ctx;
+
+ BMFace *f;
+
+ TGSET_ITER (f, node->bm_faces) {
+ BMLoop *l = f->l_first;
+
+ do {
+ l->e->head.hflag &= ~BM_ELEM_TAG;
+ l = l->next;
+ } while (l != f->l_first);
+ }
+ TGSET_ITER_END
+
+ TGSET_ITER (f, node->bm_faces) {
+#ifdef USE_EDGEQUEUE_FRONTFACE
+ if (eq_ctx->q->use_view_normal) {
+ if (dot_v3v3(f->no, eq_ctx->q->view_normal) < 0.0f) {
+ continue;
+ }
+ }
+#endif
+
+ if (eq_ctx->q->edge_queue_tri_in_range(eq_ctx->q, f)) {
+ /* Check each edge of the face */
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter = l_first;
+ do {
+#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
+ const float len_sq = calc_weighted_edge_collapse(eq_ctx, l_iter->e->v1, l_iter->e->v2);
+ if (len_sq < eq_ctx->q->limit_len_squared) {
+ long_edge_queue_edge_add_recursive_2(
+ tdata, l_iter->radial_next, l_iter, len_sq, eq_ctx->q->limit_len);
+ }
+#else
+ const float len_sq = calc_weighted_edge_split(eq_ctx, l_iter->e->v1, l_iter->e->v2);
+ if (len_sq > eq_ctx->q->limit_len_squared) {
+ edge_thread_data_insert(tdata, l_iter->e);
+ }
+#endif
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ }
+ TGSET_ITER_END
+}
+
/* Create a priority queue containing vertex pairs connected by a long
* edge as defined by PBVH.bm_max_edge_len.
*
@@ -1008,6 +1581,8 @@ static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
const bool use_projected)
{
eq_ctx->q->heap = BLI_heapsimple_new();
+ eq_ctx->q->elems = NULL;
+ eq_ctx->q->totelems = 0;
eq_ctx->q->center = center;
eq_ctx->q->radius_squared = radius * radius;
eq_ctx->q->limit_len_squared = pbvh->bm_max_edge_len * pbvh->bm_max_edge_len;
@@ -1025,32 +1600,69 @@ static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
if (use_projected) {
eq_ctx->q->edge_queue_tri_in_range = edge_queue_tri_in_circle;
+ eq_ctx->q->edge_queue_vert_in_range = edge_queue_vert_in_circle;
project_plane_normalized_v3_v3v3(eq_ctx->q->center_proj, center, view_normal);
}
else {
eq_ctx->q->edge_queue_tri_in_range = edge_queue_tri_in_sphere;
+ eq_ctx->q->edge_queue_vert_in_range = edge_queue_vert_in_sphere;
}
#ifdef USE_EDGEQUEUE_TAG_VERIFY
pbvh_bmesh_edge_tag_verify(pbvh);
#endif
+ EdgeQueueThreadData *tdata = NULL;
+ BLI_array_declare(tdata);
+
for (int n = 0; n < pbvh->totnode; n++) {
PBVHNode *node = &pbvh->nodes[n];
/* Check leaf nodes marked for topology update */
if ((node->flag & PBVH_Leaf) && (node->flag & PBVH_UpdateTopology) &&
!(node->flag & PBVH_FullyHidden)) {
- GSetIterator gs_iter;
+ EdgeQueueThreadData td;
- /* Check each face */
- GSET_ITER (gs_iter, node->bm_faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+ memset(&td, 0, sizeof(td));
+
+ td.pbvh = pbvh;
+ td.node = node;
+ td.eq_ctx = eq_ctx;
+ BLI_array_append(tdata, td);
+ /* Check each face */
+ /*
+ BMFace *f;
+ TGSET_ITER (f, node->bm_faces) {
long_edge_queue_face_add(eq_ctx, f);
}
+ TGSET_ITER_END
+ */
+ }
+ }
+
+ int count = BLI_array_len(tdata);
+
+ TaskParallelSettings settings;
+
+ BLI_parallel_range_settings_defaults(&settings);
+ BLI_task_parallel_range(0, count, tdata, long_edge_queue_task_cb, &settings);
+
+ for (int i = 0; i < count; i++) {
+ EdgeQueueThreadData *td = tdata + i;
+
+ BMEdge **edges = td->edges;
+ for (int j = 0; j < td->totedge; j++) {
+ BMEdge *e = edges[j];
+ e->head.hflag &= ~BM_ELEM_TAG;
+ edge_queue_insert(eq_ctx, e, -calc_weighted_edge_split(eq_ctx, e->v1, e->v2));
+ }
+
+ if (td->edges) {
+ MEM_freeN(td->edges);
}
}
+ BLI_array_free(tdata);
}
/* Create a priority queue containing vertex pairs connected by a
@@ -1071,6 +1683,8 @@ static void short_edge_queue_create(EdgeQueueContext *eq_ctx,
const bool use_projected)
{
eq_ctx->q->heap = BLI_heapsimple_new();
+ eq_ctx->q->elems = NULL;
+ eq_ctx->q->totelems = 0;
eq_ctx->q->center = center;
eq_ctx->q->radius_squared = radius * radius;
eq_ctx->q->limit_len_squared = pbvh->bm_min_edge_len * pbvh->bm_min_edge_len;
@@ -1088,28 +1702,67 @@ static void short_edge_queue_create(EdgeQueueContext *eq_ctx,
if (use_projected) {
eq_ctx->q->edge_queue_tri_in_range = edge_queue_tri_in_circle;
+ eq_ctx->q->edge_queue_vert_in_range = edge_queue_vert_in_circle;
project_plane_normalized_v3_v3v3(eq_ctx->q->center_proj, center, view_normal);
}
else {
eq_ctx->q->edge_queue_tri_in_range = edge_queue_tri_in_sphere;
+ eq_ctx->q->edge_queue_vert_in_range = edge_queue_vert_in_sphere;
}
+ EdgeQueueThreadData *tdata = NULL;
+ BLI_array_declare(tdata);
+
for (int n = 0; n < pbvh->totnode; n++) {
PBVHNode *node = &pbvh->nodes[n];
+ EdgeQueueThreadData td;
- /* Check leaf nodes marked for topology update */
if ((node->flag & PBVH_Leaf) && (node->flag & PBVH_UpdateTopology) &&
!(node->flag & PBVH_FullyHidden)) {
- GSetIterator gs_iter;
+ memset(&td, 0, sizeof(td));
+ td.pbvh = pbvh;
+ td.node = node;
+ td.eq_ctx = eq_ctx;
- /* Check each face */
- GSET_ITER (gs_iter, node->bm_faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+ BLI_array_append(tdata, td);
+ }
+#if 0
+ /* Check leaf nodes marked for topology update */
+ BMFace *f;
+
+ /* Check each face */
+ TGSET_ITER (f, node->bm_faces) {
short_edge_queue_face_add(eq_ctx, f);
}
+ TGSET_ITER_END
}
+#endif
}
+
+ int count = BLI_array_len(tdata);
+
+ TaskParallelSettings settings;
+
+ BLI_parallel_range_settings_defaults(&settings);
+ BLI_task_parallel_range(0, count, tdata, short_edge_queue_task_cb, &settings);
+
+ for (int i = 0; i < count; i++) {
+ EdgeQueueThreadData *td = tdata + i;
+
+ BMEdge **edges = td->edges;
+ for (int j = 0; j < td->totedge; j++) {
+ BMEdge *e = edges[j];
+ e->head.hflag &= ~BM_ELEM_TAG;
+ edge_queue_insert(eq_ctx, e, calc_weighted_edge_collapse(eq_ctx, e->v1, e->v2));
+ }
+
+ if (td->edges) {
+ MEM_freeN(td->edges);
+ }
+ }
+
+ BLI_array_free(tdata);
}
/*************************** Topology update **************************/
@@ -1119,6 +1772,8 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
BMEdge *e,
BLI_Buffer *edge_loops)
{
+ BMesh *bm = pbvh->bm;
+
float co_mid[3], no_mid[3];
/* Get all faces adjacent to the edge */
@@ -1133,6 +1788,25 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
BMVert *v_new = pbvh_bmesh_vert_create(
pbvh, node_index, co_mid, no_mid, eq_ctx->cd_vert_mask_offset);
+#ifdef DYNTOPO_CD_INTERP
+ // transfer edge flags
+
+ BMEdge *e1 = BM_edge_create(pbvh->bm, e->v1, v_new, e, BM_CREATE_NOP);
+ BMEdge *e2 = BM_edge_create(pbvh->bm, v_new, e->v2, e, BM_CREATE_NOP);
+
+ int eflag = e->head.hflag & ~BM_ELEM_HIDDEN;
+ int vflag = (e->v1->head.hflag | e->v2->head.hflag) & ~BM_ELEM_HIDDEN;
+
+ e1->head.hflag = e2->head.hflag = eflag;
+ v_new->head.hflag = vflag;
+
+ /*TODO: is it worth interpolating edge customdata?*/
+
+ void *vsrcs[2] = {e->v1->head.data, e->v2->head.data};
+ float vws[2] = {0.5f, 0.5f};
+ CustomData_bmesh_interp(&pbvh->bm->vdata, vsrcs, vws, NULL, 2, v_new->head.data);
+#endif
+
/* update paint mask */
if (eq_ctx->cd_vert_mask_offset != -1) {
float mask_v1 = BM_ELEM_CD_GET_FLOAT(e->v1, eq_ctx->cd_vert_mask_offset);
@@ -1201,31 +1875,78 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
f_new = pbvh_bmesh_face_create(pbvh, ni, v_tri, e_tri, f_adj);
long_edge_queue_face_add(eq_ctx, f_new);
+ pbvh_bmesh_copy_facedata(bm, f_new, f_adj);
+
+#ifdef DYNTOPO_CD_INTERP
+ BMLoop *lfirst = f_adj->l_first;
+ while (lfirst->v != v1) {
+ lfirst = lfirst->next;
+
+ // paranoia check
+ if (lfirst == f_adj->l_first) {
+ break;
+ }
+ }
+
+ BMLoop *l1 = lfirst;
+ BMLoop *l2 = lfirst->next;
+ BMLoop *l3 = lfirst->next->next;
+
+ void *lsrcs[2] = {l1->head.data, l2->head.data};
+ float lws[2] = {0.5f, 0.5f};
+
+ CustomData_bmesh_interp(&pbvh->bm->ldata, lsrcs, lws, lws, 2, f_new->l_first->next->head.data);
+
+ lsrcs[0] = l1->head.data;
+ lws[0] = 1.0f;
+
+ CustomData_bmesh_interp(&pbvh->bm->ldata, lsrcs, lws, lws, 1, f_new->l_first->head.data);
+
+ lsrcs[0] = l3->head.data;
+ lws[0] = 1.0f;
+
+ CustomData_bmesh_interp(&pbvh->bm->ldata, lsrcs, lws, lws, 1, f_new->l_first->prev->head.data);
+
+#endif
+
v_tri[0] = v_new;
v_tri[1] = v2;
/* v_tri[2] = v_opp; */ /* unchanged */
e_tri[0] = BM_edge_create(pbvh->bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE);
e_tri[2] = e_tri[1]; /* switched */
e_tri[1] = BM_edge_create(pbvh->bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE);
+
f_new = pbvh_bmesh_face_create(pbvh, ni, v_tri, e_tri, f_adj);
long_edge_queue_face_add(eq_ctx, f_new);
+ pbvh_bmesh_copy_facedata(bm, f_new, f_adj);
+
+#ifdef DYNTOPO_CD_INTERP
+ lsrcs[0] = lfirst->head.data;
+ lsrcs[1] = lfirst->next->head.data;
+ lws[0] = lws[1] = 0.5f;
+
+ CustomData_bmesh_interp(&pbvh->bm->ldata, lsrcs, lws, lws, 2, f_new->l_first->head.data);
+
+ lsrcs[0] = lfirst->next->head.data;
+ ;
+ lws[0] = 1.0f;
+
+ CustomData_bmesh_interp(&pbvh->bm->ldata, lsrcs, lws, lws, 1, f_new->l_first->next->head.data);
+
+ lsrcs[0] = lfirst->prev->head.data;
+ lws[0] = 1.0f;
+
+ CustomData_bmesh_interp(&pbvh->bm->ldata, lsrcs, lws, lws, 1, f_new->l_first->prev->head.data);
+#endif
+
/* Delete original */
pbvh_bmesh_face_remove(pbvh, f_adj);
BM_face_kill(pbvh->bm, f_adj);
/* Ensure new vertex is in the node */
- if (!BLI_gset_haskey(pbvh->nodes[ni].bm_unique_verts, v_new)) {
- BLI_gset_add(pbvh->nodes[ni].bm_other_verts, v_new);
- }
-
- if (BM_vert_edge_count_is_over(v_opp, 8)) {
- BMIter bm_iter;
- BMEdge *e2;
-
- BM_ITER_ELEM (e2, &bm_iter, v_opp, BM_EDGES_OF_VERT) {
- long_edge_queue_edge_add(eq_ctx, e2);
- }
+ if (!BLI_table_gset_haskey(pbvh->nodes[ni].bm_unique_verts, v_new)) {
+ BLI_table_gset_add(pbvh->nodes[ni].bm_other_verts, v_new);
}
}
@@ -1237,9 +1958,35 @@ static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx,
BLI_Buffer *edge_loops)
{
bool any_subdivided = false;
+ double time = PIL_check_seconds_timer();
+
+ RNG *rng = BLI_rng_new((int)(time * 1000.0f));
+ int step = 0;
while (!BLI_heapsimple_is_empty(eq_ctx->q->heap)) {
+ if (step++ > DYNTOPO_MAX_ITER) {
+ break;
+ }
+
+#ifdef DYNTOPO_TIME_LIMIT
+ if (PIL_check_seconds_timer() - time > DYNTOPO_TIME_LIMIT) {
+ break;
+ }
+#endif
+
+#ifndef DYNTOPO_USE_HEAP
+ if (eq_ctx->q->totelems == 0) {
+ break;
+ }
+
+ int ri = BLI_rng_get_int(rng) % eq_ctx->q->totelems;
+
+ BMVert **pair = eq_ctx->q->elems[ri];
+ eq_ctx->q->elems[ri] = eq_ctx->q->elems[eq_ctx->q->totelems - 1];
+ eq_ctx->q->totelems--;
+#else
BMVert **pair = BLI_heapsimple_pop_min(eq_ctx->q->heap);
+#endif
BMVert *v1 = pair[0], *v2 = pair[1];
BMEdge *e;
@@ -1261,7 +2008,7 @@ static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx,
continue;
}
#else
- BLI_assert(len_squared_v3v3(v1->co, v2->co) > eq_ctx->q->limit_len_squared);
+ BLI_assert(calc_weighted_edge_split(eq_ctx, v1->co, v2->co) > eq_ctx->q->limit_len_squared);
#endif
/* Check that the edge's vertices are still in the PBVH. It's
@@ -1278,10 +2025,25 @@ static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx,
pbvh_bmesh_split_edge(eq_ctx, pbvh, e, edge_loops);
}
+#if !defined(DYNTOPO_USE_HEAP) && defined(USE_EDGEQUEUE_TAG)
+ for (int i = 0; i < eq_ctx->q->totelems; i++) {
+ BMVert **pair = eq_ctx->q->elems[i];
+ BMVert *v1 = pair[0], *v2 = pair[1];
+
+ BMEdge *e = BM_edge_exists(v1, v2);
+
+ if (e) {
+ EDGE_QUEUE_DISABLE(e);
+ }
+ }
+#endif
+
#ifdef USE_EDGEQUEUE_TAG_VERIFY
pbvh_bmesh_edge_tag_verify(pbvh);
#endif
+ BLI_rng_free(rng);
+
return any_subdivided;
}
@@ -1295,6 +2057,27 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
{
BMVert *v_del, *v_conn;
+#ifdef DYNTOPO_CD_INTERP
+ if (BM_elem_flag_test(e, BM_ELEM_SEAM)) {
+ for (int step = 0; step < 2; step++) {
+ int count = 0;
+ BMVert *v = step ? v2 : v1;
+ BMIter iter;
+ BMEdge *e2;
+
+ BM_ITER_ELEM (e2, &iter, v, BM_EDGES_OF_VERT) {
+ if (BM_elem_flag_test(e2, BM_ELEM_SEAM)) {
+ count++;
+ }
+ }
+
+ if (count < 2) {
+ return;
+ }
+ }
+ }
+#endif
+
/* one of the two vertices may be masked, select the correct one for deletion */
if (BM_ELEM_CD_GET_FLOAT(v1, eq_ctx->cd_vert_mask_offset) <
BM_ELEM_CD_GET_FLOAT(v2, eq_ctx->cd_vert_mask_offset)) {
@@ -1314,6 +2097,29 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
while ((l_adj = e->l)) {
BMFace *f_adj = l_adj->f;
+#ifdef DYNTOPO_CD_INTERP
+ int eflag = 0;
+
+ // propegate flags to merged edges
+ BMLoop *l = f_adj->l_first;
+ do {
+ BMEdge *e2 = l->e;
+
+ if (e2 != e) {
+ eflag |= e2->head.hflag & ~BM_ELEM_HIDDEN;
+ }
+
+ l = l->next;
+ } while (l != f_adj->l_first);
+
+ do {
+ BMEdge *e2 = l->e;
+ e2->head.hflag |= eflag;
+
+ l = l->next;
+ } while (l != f_adj->l_first);
+#endif
+
pbvh_bmesh_face_remove(pbvh, f_adj);
BM_face_kill(pbvh->bm, f_adj);
}
@@ -1329,7 +2135,53 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
* really buy anything. */
BLI_buffer_clear(deleted_faces);
+#define MAX_LS 24
+
BMLoop *l;
+#if 1 // def DYNTOPO_CD_INTERP
+ BMLoop *ls[MAX_LS];
+
+ int totl = 0;
+
+ BM_LOOPS_OF_VERT_ITER_BEGIN (l, v_del) {
+ if (totl >= MAX_LS) {
+ break;
+ }
+ ls[totl++] = l;
+ }
+ BM_LOOPS_OF_VERT_ITER_END;
+
+ BM_LOOPS_OF_VERT_ITER_BEGIN (l, v_conn) {
+ if (totl >= MAX_LS) {
+ break;
+ }
+ ls[totl++] = l;
+ }
+ BM_LOOPS_OF_VERT_ITER_END;
+
+ void *blocks[MAX_LS];
+ float ws[MAX_LS], w = totl > 1 ? 1.0f / (float)(totl - 1) : 1.0f;
+
+ for (int i = 0; i < totl - 1; i++) {
+ blocks[i] = ls[i + 1]->head.data;
+ ws[i] = w;
+ }
+
+ if (totl > 1) {
+ CustomData_bmesh_interp(&pbvh->bm->ldata, blocks, ws, NULL, totl - 1, ls[0]->head.data);
+
+ BM_LOOPS_OF_VERT_ITER_BEGIN (l, v_del) {
+ CustomData_bmesh_copy_data(
+ &pbvh->bm->ldata, &pbvh->bm->ldata, ls[0]->head.data, &l->head.data);
+ }
+ BM_LOOPS_OF_VERT_ITER_END;
+ BM_LOOPS_OF_VERT_ITER_BEGIN (l, v_conn) {
+ CustomData_bmesh_copy_data(
+ &pbvh->bm->ldata, &pbvh->bm->ldata, ls[0]->head.data, &l->head.data);
+ }
+ BM_LOOPS_OF_VERT_ITER_END;
+ }
+#endif
BM_LOOPS_OF_VERT_ITER_BEGIN (l, v_del) {
BMFace *existing_face;
@@ -1368,11 +2220,26 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
PBVHNode *n = pbvh_bmesh_node_from_face(pbvh, f);
int ni = n - pbvh->nodes;
bm_edges_from_tri(pbvh->bm, v_tri, e_tri);
- pbvh_bmesh_face_create(pbvh, ni, v_tri, e_tri, f);
+ BMFace *f2 = pbvh_bmesh_face_create(pbvh, ni, v_tri, e_tri, f);
+
+#ifdef DYNTOPO_CD_INTERP
+ BMLoop *l2 = f2->l_first;
+ // sync edge flags
+ l2->e->head.hflag |= (l->e->head.hflag & ~BM_ELEM_HIDDEN);
+ // l2->prev->e->head.hflag |= (l->prev->e->head.hflag & ~BM_ELEM_HIDDEN);
+
+ pbvh_bmesh_copy_facedata(pbvh->bm, f2, f);
+
+ CustomData_bmesh_copy_data(&pbvh->bm->ldata, &pbvh->bm->ldata, l->head.data, &l2->head.data);
+ CustomData_bmesh_copy_data(
+ &pbvh->bm->ldata, &pbvh->bm->ldata, l->next->head.data, &l2->next->head.data);
+ CustomData_bmesh_copy_data(
+ &pbvh->bm->ldata, &pbvh->bm->ldata, l->prev->head.data, &l2->prev->head.data);
+#endif
/* Ensure that v_conn is in the new face's node */
- if (!BLI_gset_haskey(n->bm_unique_verts, v_conn)) {
- BLI_gset_add(n->bm_other_verts, v_conn);
+ if (!BLI_table_gset_haskey(n->bm_unique_verts, v_conn)) {
+ BLI_table_gset_add(n->bm_other_verts, v_conn);
}
}
@@ -1430,7 +2297,12 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
/* Move v_conn to the midpoint of v_conn and v_del (if v_conn still exists, it
* may have been deleted above) */
if (v_conn != NULL) {
- BM_log_vert_before_modified(pbvh->bm_log, v_conn, eq_ctx->cd_vert_mask_offset);
+ // log vert in bmlog, but don't update original customata layers, we want them to be
+ // interpolated
+ BM_log_vert_before_modified(pbvh->bm_log, v_conn, eq_ctx->cd_vert_mask_offset, true);
+ // void *dummy;
+ // BKE_pbvh_bmesh_update_origvert(pbvh, v_conn, &dummy, &dummy, &dummy);
+
mid_v3_v3v3(v_conn->co, v_conn->co, v_del->co);
add_v3_v3(v_conn->no, v_del->no);
normalize_v3(v_conn->no);
@@ -1452,6 +2324,44 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
BM_vert_kill(pbvh->bm, v_del);
}
+void BKE_pbvh_bmesh_update_origvert(
+ PBVH *pbvh, BMVert *v, float **r_co, float **r_no, float **r_color)
+{
+ float *co = NULL, *no = NULL;
+
+ BM_log_vert_before_modified(pbvh->bm_log, v, pbvh->cd_vert_mask_offset, r_color != NULL);
+
+ if (r_co || r_no) {
+ co = BM_ELEM_CD_GET_VOID_P(v, pbvh->cd_origco_offset);
+ no = BM_ELEM_CD_GET_VOID_P(v, pbvh->cd_origno_offset);
+
+ copy_v3_v3(co, v->co);
+ copy_v3_v3(no, v->no);
+
+ if (r_co) {
+ *r_co = co;
+ }
+
+ if (r_no) {
+ *r_no = no;
+ }
+ }
+
+ if (r_color && pbvh->cd_vcol_offset >= 0 && pbvh->cd_origvcol_offset >= 0) {
+ MPropCol *ml1 = BM_ELEM_CD_GET_VOID_P(v, pbvh->cd_vcol_offset);
+ MPropCol *ml2 = BM_ELEM_CD_GET_VOID_P(v, pbvh->cd_origvcol_offset);
+
+ copy_v4_v4(ml2->color, ml1->color);
+
+ if (r_color) {
+ *r_color = ml2->color;
+ }
+ }
+ else if (r_color) {
+ *r_color = NULL;
+ }
+}
+
static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx,
PBVH *pbvh,
BLI_Buffer *deleted_faces)
@@ -1461,8 +2371,39 @@ static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx,
/* deleted verts point to vertices they were merged into, or NULL when removed. */
GHash *deleted_verts = BLI_ghash_ptr_new("deleted_verts");
+ double time = PIL_check_seconds_timer();
+ RNG *rng = BLI_rng_new(time * 1000.0f);
+
+//#define TEST_COLLAPSE
+#ifdef TEST_COLLAPSE
+ int _i = 0;
+#endif
+
+ int step = 0;
+
while (!BLI_heapsimple_is_empty(eq_ctx->q->heap)) {
+ if (step++ > DYNTOPO_MAX_ITER) {
+ break;
+ }
+#ifdef DYNTOPO_TIME_LIMIT
+ if (PIL_check_seconds_timer() - time > DYNTOPO_TIME_LIMIT) {
+ break;
+ }
+#endif
+
+#ifndef DYNTOPO_USE_HEAP
+ if (eq_ctx->q->totelems == 0) {
+ break;
+ }
+
+ int ri = BLI_rng_get_int(rng) % eq_ctx->q->totelems;
+
+ BMVert **pair = eq_ctx->q->elems[ri];
+ eq_ctx->q->elems[ri] = eq_ctx->q->elems[eq_ctx->q->totelems - 1];
+ eq_ctx->q->totelems--;
+#else
BMVert **pair = BLI_heapsimple_pop_min(eq_ctx->q->heap);
+#endif
BMVert *v1 = pair[0], *v2 = pair[1];
BLI_mempool_free(eq_ctx->pool, pair);
pair = NULL;
@@ -1482,7 +2423,7 @@ static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx,
EDGE_QUEUE_DISABLE(e);
#endif
- if (len_squared_v3v3(v1->co, v2->co) >= min_len_squared) {
+ if (calc_weighted_edge_collapse(eq_ctx, v1, v2) >= min_len_squared) {
continue;
}
@@ -1498,8 +2439,32 @@ static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx,
any_collapsed = true;
pbvh_bmesh_collapse_edge(pbvh, e, v1, v2, deleted_verts, deleted_faces, eq_ctx);
+
+#ifdef TEST_COLLAPSE
+ if (_i++ > 10) {
+ break;
+ }
+#endif
}
+#if !defined(DYNTOPO_USE_HEAP) && defined(USE_EDGEQUEUE_TAG)
+ for (int i = 0; i < eq_ctx->q->totelems; i++) {
+ BMVert **pair = eq_ctx->q->elems[i];
+ BMVert *v1 = pair[0], *v2 = pair[1];
+
+ /* Check the verts still exist */
+ if (!(v1 = bm_vert_hash_lookup_chain(deleted_verts, v1)) ||
+ !(v2 = bm_vert_hash_lookup_chain(deleted_verts, v2)) || (v1 == v2)) {
+ continue;
+ }
+
+ BMEdge *e = BM_edge_exists(v1, v2);
+ if (e) {
+ EDGE_QUEUE_DISABLE(e);
+ }
+ }
+#endif
+ BLI_rng_free(rng);
BLI_ghash_free(deleted_verts, NULL, NULL);
return any_collapsed;
@@ -1513,7 +2478,8 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node,
struct IsectRayPrecalc *isect_precalc,
float *depth,
bool use_original,
- int *r_active_vertex_index,
+ SculptVertRef *r_active_vertex_index,
+ SculptFaceRef *r_active_face_index,
float *r_face_normal)
{
bool hit = false;
@@ -1522,29 +2488,69 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node,
if (use_original && node->bm_tot_ortri) {
for (int i = 0; i < node->bm_tot_ortri; i++) {
const int *t = node->bm_ortri[i];
- hit |= ray_face_intersection_tri(ray_start,
- isect_precalc,
- node->bm_orco[t[0]],
- node->bm_orco[t[1]],
- node->bm_orco[t[2]],
- depth);
+
+ bool hit2 = ray_face_intersection_tri(ray_start,
+ isect_precalc,
+ node->bm_orco[t[0]],
+ node->bm_orco[t[1]],
+ node->bm_orco[t[2]],
+ depth);
+
+ // ensure sculpt active vertex is set r_active_vertex_index
+ if (hit2) {
+ int k = 0;
+ BMFace *f = NULL;
+
+ TGSET_ITER_INDEX(f, node->bm_faces, k)
+ {
+ if (k == i) {
+ break;
+ }
+ }
+ TGSET_ITER_INDEX_END
+
+ if (!f) {
+ continue;
+ }
+
+ BMLoop *l = f->l_first;
+
+ for (int j = 0; j < 3; j++, l = l->next) {
+ float dist = len_squared_v3v3(node->bm_orco[t[j]], ray_start);
+
+ if (!hit || dist < len_squared_v3v3(ray_start, nearest_vertex_co)) {
+ int idx = t[j];
+
+ hit = true;
+ copy_v3_v3(nearest_vertex_co, node->bm_orco[t[j]]);
+
+ if (r_active_vertex_index) {
+ *r_active_vertex_index = BKE_pbvh_make_vref((intptr_t)l->v);
+ }
+
+ if (r_active_face_index) {
+ *r_active_face_index = BKE_pbvh_make_fref((intptr_t)l->f);
+ }
+ }
+ }
+ }
+
+ hit = true;
}
}
else {
- GSetIterator gs_iter;
-
- GSET_ITER (gs_iter, node->bm_faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+ BMFace *f;
+ TGSET_ITER (f, node->bm_faces) {
BLI_assert(f->len == 3);
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
BMVert *v_tri[3];
BM_face_as_array_vert_tri(f, v_tri);
+ bool hit2;
- if (ray_face_intersection_tri(
+ if (hit2 = ray_face_intersection_tri(
ray_start, isect_precalc, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co, depth)) {
- hit = true;
if (r_face_normal) {
normal_tri_v3(r_face_normal, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co);
@@ -1553,17 +2559,26 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node,
if (r_active_vertex_index) {
float location[3] = {0.0f};
madd_v3_v3v3fl(location, ray_start, ray_normal, *depth);
+
for (int j = 0; j < 3; j++) {
- if (len_squared_v3v3(location, v_tri[j]->co) <
- len_squared_v3v3(location, nearest_vertex_co)) {
+ if (!hit || len_squared_v3v3(location, v_tri[j]->co) <
+ len_squared_v3v3(location, nearest_vertex_co)) {
copy_v3_v3(nearest_vertex_co, v_tri[j]->co);
- *r_active_vertex_index = BM_elem_index_get(v_tri[j]);
+ SculptVertRef vref = {(intptr_t)v_tri[j]}; // BM_elem_index_get(v_tri[j]);
+ *r_active_vertex_index = vref;
+
+ if (r_active_face_index) {
+ *r_active_face_index = BKE_pbvh_make_fref((intptr_t)f);
+ }
}
}
}
+
+ hit = true;
}
}
}
+ TGSET_ITER_END
}
return hit;
@@ -1579,14 +2594,13 @@ bool BKE_pbvh_bmesh_node_raycast_detail(PBVHNode *node,
return 0;
}
- GSetIterator gs_iter;
+ BMFace *f;
bool hit = false;
BMFace *f_hit = NULL;
- GSET_ITER (gs_iter, node->bm_faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
-
+ TGSET_ITER (f, node->bm_faces) {
BLI_assert(f->len == 3);
+
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
BMVert *v_tri[3];
bool hit_local;
@@ -1600,6 +2614,7 @@ bool BKE_pbvh_bmesh_node_raycast_detail(PBVHNode *node,
}
}
}
+ TGSET_ITER_END
if (hit) {
BMVert *v_tri[3];
@@ -1637,11 +2652,9 @@ bool pbvh_bmesh_node_nearest_to_ray(PBVHNode *node,
}
}
else {
- GSetIterator gs_iter;
-
- GSET_ITER (gs_iter, node->bm_faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+ BMFace *f;
+ TGSET_ITER (f, node->bm_faces) {
BLI_assert(f->len == 3);
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
BMVert *v_tri[3];
@@ -1651,6 +2664,7 @@ bool pbvh_bmesh_node_nearest_to_ray(PBVHNode *node,
ray_start, ray_normal, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co, depth, dist_sq);
}
}
+ TGSET_ITER_END
}
return hit;
@@ -1662,18 +2676,25 @@ void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode)
PBVHNode *node = nodes[n];
if (node->flag & PBVH_UpdateNormals) {
- GSetIterator gs_iter;
+ BMVert *v;
+ BMFace *f;
- GSET_ITER (gs_iter, node->bm_faces) {
- BM_face_normal_update(BLI_gsetIterator_getKey(&gs_iter));
+ TGSET_ITER (f, node->bm_faces) {
+ BM_face_normal_update(f);
}
- GSET_ITER (gs_iter, node->bm_unique_verts) {
- BM_vert_normal_update(BLI_gsetIterator_getKey(&gs_iter));
+ TGSET_ITER_END
+
+ TGSET_ITER (v, node->bm_unique_verts) {
+ BM_vert_normal_update(v);
}
+ TGSET_ITER_END
+
/* This should be unneeded normally */
- GSET_ITER (gs_iter, node->bm_other_verts) {
- BM_vert_normal_update(BLI_gsetIterator_getKey(&gs_iter));
+ TGSET_ITER (v, node->bm_other_verts) {
+ BM_vert_normal_update(v);
}
+ TGSET_ITER_END
+
node->flag &= ~PBVH_UpdateNormals;
}
}
@@ -1818,11 +2839,11 @@ static void pbvh_bmesh_create_nodes_fast_recursive(
bool has_visible = false;
n->flag = PBVH_Leaf;
- n->bm_faces = BLI_gset_ptr_new_ex("bm_faces", node->totface);
+ n->bm_faces = BLI_table_gset_new_ex("bm_faces", node->totface);
/* Create vert hash sets */
- n->bm_unique_verts = BLI_gset_ptr_new("bm_unique_verts");
- n->bm_other_verts = BLI_gset_ptr_new("bm_other_verts");
+ n->bm_unique_verts = BLI_table_gset_new("bm_unique_verts");
+ n->bm_other_verts = BLI_table_gset_new("bm_other_verts");
BB_reset(&n->vb);
@@ -1833,7 +2854,7 @@ static void pbvh_bmesh_create_nodes_fast_recursive(
BBC *bbc = &bbc_array[BM_elem_index_get(f)];
/* Update ownership of faces */
- BLI_gset_insert(n->bm_faces, f);
+ BLI_table_gset_insert(n->bm_faces, f);
BM_ELEM_CD_SET_INT(f, cd_face_node_offset, node_index);
/* Update vertices */
@@ -1841,12 +2862,12 @@ static void pbvh_bmesh_create_nodes_fast_recursive(
BMLoop *l_iter = l_first;
do {
BMVert *v = l_iter->v;
- if (!BLI_gset_haskey(n->bm_unique_verts, v)) {
+ if (!BLI_table_gset_haskey(n->bm_unique_verts, v)) {
if (BM_ELEM_CD_GET_INT(v, cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
- BLI_gset_add(n->bm_other_verts, v);
+ BLI_table_gset_add(n->bm_other_verts, v);
}
else {
- BLI_gset_insert(n->bm_unique_verts, v);
+ BLI_table_gset_insert(n->bm_unique_verts, v);
BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, node_index);
}
}
@@ -1881,20 +2902,52 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh,
bool smooth_shading,
BMLog *log,
const int cd_vert_node_offset,
- const int cd_face_node_offset)
+ const int cd_face_node_offset,
+ const int cd_origco_offset,
+ const int cd_origno_offset,
+ const int cd_origvcol_offset)
{
pbvh->cd_vert_node_offset = cd_vert_node_offset;
pbvh->cd_face_node_offset = cd_face_node_offset;
+ pbvh->cd_origco_offset = cd_origco_offset;
+ pbvh->cd_origno_offset = cd_origno_offset;
+ pbvh->cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
+ pbvh->cd_origvcol_offset = cd_origvcol_offset;
+
pbvh->bm = bm;
BKE_pbvh_bmesh_detail_size_set(pbvh, 0.75);
pbvh->type = PBVH_BMESH;
pbvh->bm_log = log;
+ pbvh->cd_vcol_offset = CustomData_get_offset(&bm->vdata, CD_PROP_COLOR);
+ pbvh->cd_faceset_offset = CustomData_get_offset(&bm->pdata, CD_SCULPT_FACE_SETS);
/* TODO: choose leaf limit better */
- pbvh->leaf_limit = 100;
+ pbvh->leaf_limit = 1000;
+
+ BMIter iter;
+ BMVert *v;
+
+ int cd_vcol_offset = -1;
+ if (cd_origvcol_offset >= 0) {
+ cd_vcol_offset = CustomData_get_offset(&bm->vdata, CD_PROP_COLOR);
+ }
+
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ float *co = BM_ELEM_CD_GET_VOID_P(v, cd_origco_offset);
+ float *no = BM_ELEM_CD_GET_VOID_P(v, cd_origno_offset);
+
+ copy_v3_v3(co, v->co);
+ copy_v3_v3(no, v->no);
+ if (cd_origvcol_offset >= 0) {
+ MPropCol *c1 = BM_ELEM_CD_GET_VOID_P(v, cd_vcol_offset);
+ MPropCol *c2 = BM_ELEM_CD_GET_VOID_P(v, cd_origvcol_offset);
+
+ copy_v4_v4(c2->color, c1->color);
+ }
+ }
if (smooth_shading) {
pbvh->flags |= PBVH_DYNTOPO_SMOOTH_SHADING;
}
@@ -1904,7 +2957,6 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh,
BMFace **nodeinfo = MEM_mallocN(sizeof(*nodeinfo) * bm->totface, "nodeinfo");
MemArena *arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "fast PBVH node storage");
- BMIter iter;
BMFace *f;
int i;
BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) {
@@ -1926,7 +2978,6 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh,
/* Likely this is already dirty. */
bm->elem_index_dirty |= BM_FACE;
- BMVert *v;
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE);
}
@@ -1953,6 +3004,52 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh,
MEM_freeN(nodeinfo);
}
+static double last_update_time[128] = {
+ 0,
+};
+
+bool BKE_pbvh_bmesh_update_topology_nodes(PBVH *pbvh,
+ bool (*searchcb)(PBVHNode *node, void *data),
+ void (*undopush)(PBVHNode *node, void *data),
+ void *searchdata,
+ PBVHTopologyUpdateMode mode,
+ const float center[3],
+ const float view_normal[3],
+ float radius,
+ const bool use_frontface,
+ const bool use_projected,
+ int sym_axis,
+ bool updatePBVH)
+{
+ bool modified = false;
+
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *node = pbvh->nodes + i;
+
+ if (!(node->flag & PBVH_Leaf) || !searchcb(node, searchdata)) {
+ continue;
+ }
+
+ if (node->flag & PBVH_Leaf) {
+ undopush(node, searchdata);
+
+ BKE_pbvh_node_mark_topology_update(pbvh->nodes + i);
+ BKE_pbvh_bmesh_node_save_ortri(pbvh->bm, pbvh->nodes + i);
+ }
+ }
+
+ modified = modified || BKE_pbvh_bmesh_update_topology(pbvh,
+ mode,
+ center,
+ view_normal,
+ radius,
+ use_frontface,
+ use_projected,
+ sym_axis,
+ updatePBVH);
+ return modified;
+}
+
/* Collapse short edges, subdivide long edges */
bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
PBVHTopologyUpdateMode mode,
@@ -1960,8 +3057,20 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
const float view_normal[3],
float radius,
const bool use_frontface,
- const bool use_projected)
+ const bool use_projected,
+ int sym_axis,
+ bool updatePBVH)
{
+ /*
+ if (sym_axis >= 0 &&
+ PIL_check_seconds_timer() - last_update_time[sym_axis] < DYNTOPO_RUN_INTERVAL) {
+ return false;
+ }
+
+ if (sym_axis >= 0) {
+ last_update_time[sym_axis] = PIL_check_seconds_timer();
+ }*/
+
/* 2 is enough for edge faces - manifold edge */
BLI_buffer_declare_static(BMLoop *, edge_loops, BLI_BUFFER_NOP, 2);
BLI_buffer_declare_static(BMFace *, deleted_faces, BLI_BUFFER_NOP, 32);
@@ -1974,7 +3083,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
if (view_normal) {
BLI_assert(len_squared_v3(view_normal) != 0.0f);
}
-
+#if 1
if (mode & PBVH_Collapse) {
EdgeQueue q;
BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *) * 2, 0, 128, BLI_MEMPOOL_NOP);
@@ -1991,6 +3100,9 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
&eq_ctx, pbvh, center, view_normal, radius, use_frontface, use_projected);
modified |= pbvh_bmesh_collapse_short_edges(&eq_ctx, pbvh, &deleted_faces);
BLI_heapsimple_free(q.heap, NULL);
+ if (q.elems) {
+ MEM_freeN(q.elems);
+ }
BLI_mempool_destroy(queue_pool);
}
@@ -2009,18 +3121,51 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
long_edge_queue_create(
&eq_ctx, pbvh, center, view_normal, radius, use_frontface, use_projected);
modified |= pbvh_bmesh_subdivide_long_edges(&eq_ctx, pbvh, &edge_loops);
+ if (q.elems) {
+ MEM_freeN(q.elems);
+ }
BLI_heapsimple_free(q.heap, NULL);
BLI_mempool_destroy(queue_pool);
}
+#endif
+ if (modified) {
- /* Unmark nodes */
- for (int n = 0; n < pbvh->totnode; n++) {
- PBVHNode *node = &pbvh->nodes[n];
+#ifdef PROXY_ADVANCED
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *node = pbvh->nodes + i;
+
+ // ensure proxyvert arrays are rebuilt
+ if (node->flag & PBVH_Leaf) {
+ BKE_pbvh_free_proxyarray(pbvh, node);
+ }
+ }
+#endif
+
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *node = pbvh->nodes + i;
+
+ if ((node->flag & PBVH_Leaf) && (node->flag & PBVH_UpdateTopology) &&
+ !(node->flag & PBVH_FullyHidden)) {
+ node->flag &= ~PBVH_UpdateTopology;
+
+ /* Recursively split nodes that have gotten too many
+ * elements */
+ if (updatePBVH) {
+ pbvh_bmesh_node_limit_ensure(pbvh, i);
+ }
+ }
+ }
+ }
+ else { // still unmark nodes
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *node = pbvh->nodes + i;
- if (node->flag & PBVH_Leaf && node->flag & PBVH_UpdateTopology) {
- node->flag &= ~PBVH_UpdateTopology;
+ if ((node->flag & PBVH_Leaf) && (node->flag & PBVH_UpdateTopology)) {
+ node->flag &= ~PBVH_UpdateTopology;
+ }
}
}
+
BLI_buffer_free(&edge_loops);
BLI_buffer_free(&deleted_faces);
@@ -2035,43 +3180,45 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
* (currently just raycast), store the node's triangles and vertices.
*
* Skips triangles that are hidden. */
-void BKE_pbvh_bmesh_node_save_orig(BMesh *bm, PBVHNode *node)
+void BKE_pbvh_bmesh_node_save_ortri(BMesh *bm, PBVHNode *node)
{
/* Skip if original coords/triangles are already saved */
if (node->bm_orco) {
return;
}
- const int totvert = BLI_gset_len(node->bm_unique_verts) + BLI_gset_len(node->bm_other_verts);
+ const int totvert = BLI_table_gset_len(node->bm_unique_verts) +
+ BLI_table_gset_len(node->bm_other_verts);
- const int tottri = BLI_gset_len(node->bm_faces);
+ const int tottri = BLI_table_gset_len(node->bm_faces);
node->bm_orco = MEM_mallocN(sizeof(*node->bm_orco) * totvert, __func__);
node->bm_ortri = MEM_mallocN(sizeof(*node->bm_ortri) * tottri, __func__);
/* Copy out the vertices and assign a temporary index */
int i = 0;
- GSetIterator gs_iter;
- GSET_ITER (gs_iter, node->bm_unique_verts) {
- BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
+ BMVert *v;
+ TGSET_ITER (v, node->bm_unique_verts) {
copy_v3_v3(node->bm_orco[i], v->co);
BM_elem_index_set(v, i); /* set_dirty! */
i++;
}
- GSET_ITER (gs_iter, node->bm_other_verts) {
- BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
+ TGSET_ITER_END
+
+ TGSET_ITER (v, node->bm_other_verts) {
copy_v3_v3(node->bm_orco[i], v->co);
BM_elem_index_set(v, i); /* set_dirty! */
i++;
}
+ TGSET_ITER_END
+
/* Likely this is already dirty. */
bm->elem_index_dirty |= BM_VERT;
/* Copy the triangles */
i = 0;
- GSET_ITER (gs_iter, node->bm_faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
-
+ BMFace *f;
+ TGSET_ITER (f, node->bm_faces) {
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
continue;
}
@@ -2089,13 +3236,373 @@ void BKE_pbvh_bmesh_node_save_orig(BMesh *bm, PBVHNode *node)
#endif
i++;
}
+ TGSET_ITER_END
node->bm_tot_ortri = i;
}
+static int pbvh_count_subtree_verts(PBVH *pbvh, PBVHNode *n)
+{
+ if (n->flag & PBVH_Leaf) {
+ n->subtree_tottri = BLI_table_gset_len(
+ n->bm_faces); // n->tm_unique_verts->length + n->tm_other_verts->length;
+ return n->subtree_tottri;
+ }
+
+ int ni = n->children_offset;
+
+ int ret = pbvh_count_subtree_verts(pbvh, pbvh->nodes + ni);
+ ret += pbvh_count_subtree_verts(pbvh, pbvh->nodes + ni + 1);
+
+ n->subtree_tottri = ret;
+
+ return ret;
+}
+
+static void pbvh_bmesh_join_subnodes(PBVH *pbvh, PBVHNode *node, PBVHNode *parent)
+{
+ if (!(node->flag & PBVH_Leaf)) {
+ int ni = node->children_offset;
+
+ if (ni > 0 && ni < pbvh->totnode - 1) {
+ pbvh_bmesh_join_subnodes(pbvh, pbvh->nodes + ni, parent);
+ pbvh_bmesh_join_subnodes(pbvh, pbvh->nodes + ni + 1, parent);
+ }
+ else {
+ printf("node corruption: %d\n", ni);
+ return;
+ }
+ if (node != parent) {
+ node->flag |= PBVH_Delete; // mark for deletion
+ }
+
+ return;
+ }
+
+ if (node != parent) {
+ node->flag |= PBVH_Delete; // mark for deletion
+ }
+
+ BMVert *v;
+
+ TGSET_ITER (v, node->bm_unique_verts) {
+ BLI_table_gset_add(parent->bm_unique_verts, v);
+
+ BM_ELEM_CD_SET_INT(v, pbvh->cd_vert_node_offset, DYNTOPO_NODE_NONE);
+ }
+ TGSET_ITER_END
+
+ // printf(" subtotface: %d\n", BLI_table_gset_len(node->bm_faces));
+
+ BMFace *f;
+ TGSET_ITER (f, node->bm_faces) {
+ BLI_table_gset_add(parent->bm_faces, f);
+ BM_ELEM_CD_SET_INT(f, pbvh->cd_face_node_offset, DYNTOPO_NODE_NONE);
+ }
+ TGSET_ITER_END
+}
+
+static void BKE_pbvh_bmesh_corect_tree(PBVH *pbvh, PBVHNode *node, PBVHNode *parent)
+{
+ const int size_lower = pbvh->leaf_limit - (pbvh->leaf_limit >> 1);
+ const int size_higher = pbvh->leaf_limit + (pbvh->leaf_limit >> 1);
+
+ if (node->flag & PBVH_Leaf) {
+ // pbvh_trimesh_node_limit_ensure(pbvh, (int)(node - pbvh->nodes));
+ return;
+
+ // join nodes if subtree lacks verts, unless node is root
+ }
+
+ if (node->subtree_tottri < size_lower && node != pbvh->nodes) {
+ node->bm_unique_verts = BLI_table_gset_new("bm_unique_verts");
+ node->bm_other_verts = BLI_table_gset_new("bm_other_verts");
+ node->bm_faces = BLI_table_gset_new("bm_faces");
+
+ pbvh_bmesh_join_subnodes(pbvh, pbvh->nodes + node->children_offset, node);
+ pbvh_bmesh_join_subnodes(pbvh, pbvh->nodes + node->children_offset + 1, node);
+
+ node->children_offset = 0;
+ node->flag |= PBVH_Leaf | PBVH_UpdateRedraw | PBVH_UpdateBB | PBVH_UpdateDrawBuffers |
+ PBVH_RebuildDrawBuffers | PBVH_UpdateOriginalBB | PBVH_UpdateMask |
+ PBVH_UpdateVisibility | PBVH_UpdateColor | PBVH_UpdateTopology |
+ PBVH_UpdateNormals;
+
+ TableGSet *other = BLI_table_gset_new(__func__);
+ BMVert *v;
+
+ node->children_offset = 0;
+ node->draw_buffers = NULL;
+
+ // rebuild bm_other_verts
+ BMFace *f;
+ TGSET_ITER (f, node->bm_faces) {
+ BMLoop *l = f->l_first;
+
+ BM_ELEM_CD_SET_INT(f, pbvh->cd_face_node_offset, DYNTOPO_NODE_NONE);
+
+ do {
+ if (!BLI_table_gset_haskey(node->bm_unique_verts, l->v)) {
+ BLI_table_gset_add(other, l->v);
+ }
+ l = l->next;
+ } while (l != f->l_first);
+ }
+ TGSET_ITER_END
+
+ BLI_table_gset_free(node->bm_other_verts, NULL);
+ node->bm_other_verts = other;
+
+ BB_reset(&node->vb);
+
+#if 1
+ TGSET_ITER (v, node->bm_unique_verts) {
+ BB_expand(&node->vb, v->co);
+ }
+ TGSET_ITER_END
+
+ TGSET_ITER (v, node->bm_other_verts) {
+ BB_expand(&node->vb, v->co);
+ }
+ TGSET_ITER_END
+#endif
+
+ // printf("totface: %d\n", BLI_table_gset_len(node->bm_faces));
+ node->orig_vb = node->vb;
+
+ return;
+ }
+
+ int ni = node->children_offset;
+
+ for (int i = 0; i < 2; i++, ni++) {
+ PBVHNode *child = pbvh->nodes + ni;
+ BKE_pbvh_bmesh_corect_tree(pbvh, child, node);
+ }
+}
+
+static void pbvh_bmesh_join_nodes(PBVH *bvh)
+{
+ pbvh_count_subtree_verts(bvh, bvh->nodes);
+ BKE_pbvh_bmesh_corect_tree(bvh, bvh->nodes, NULL);
+
+ // compact nodes
+ int totnode = 0;
+ for (int i = 0; i < bvh->totnode; i++) {
+ PBVHNode *n = bvh->nodes + i;
+
+ if (!(n->flag & PBVH_Delete)) {
+ if (!(n->flag & PBVH_Leaf)) {
+ PBVHNode *n1 = bvh->nodes + n->children_offset;
+ PBVHNode *n2 = bvh->nodes + n->children_offset + 1;
+
+ if ((n1->flag & PBVH_Delete) != (n2->flag & PBVH_Delete)) {
+ printf("un-deleting an empty node\n");
+ PBVHNode *n3 = n1->flag & PBVH_Delete ? n1 : n2;
+
+ n3->flag = PBVH_Leaf;
+ n3->bm_unique_verts = BLI_table_gset_new("bm_unique_verts");
+ n3->bm_other_verts = BLI_table_gset_new("bm_other_verts");
+ n3->bm_faces = BLI_table_gset_new("bm_faces");
+ }
+ else if ((n1->flag & PBVH_Delete) && (n2->flag & PBVH_Delete)) {
+ n->children_offset = 0;
+ n->flag |= PBVH_Leaf;
+
+ if (!n->bm_unique_verts) {
+ // should not happen
+ n->bm_unique_verts = BLI_table_gset_new("bm_unique_verts");
+ n->bm_other_verts = BLI_table_gset_new("bm_other_verts");
+ n->bm_faces = BLI_table_gset_new("bm_faces");
+ }
+ }
+ }
+
+ totnode++;
+ }
+ }
+
+ int *map = MEM_callocN(sizeof(int) * bvh->totnode, "bmesh map temp");
+
+ // build idx map for child offsets
+ int j = 0;
+ for (int i = 0; i < bvh->totnode; i++) {
+ PBVHNode *n = bvh->nodes + i;
+
+ if (!(n->flag & PBVH_Delete)) {
+ map[i] = j++;
+ }
+ else if (1) {
+ if (n->layer_disp) {
+ MEM_freeN(n->layer_disp);
+ n->layer_disp = NULL;
+ }
+ if (n->draw_buffers) {
+ GPU_pbvh_buffers_free(n->draw_buffers);
+ n->draw_buffers = NULL;
+ }
+ if (n->vert_indices) {
+ MEM_freeN((void *)n->vert_indices);
+ n->vert_indices = NULL;
+ }
+ if (n->face_vert_indices) {
+ MEM_freeN((void *)n->face_vert_indices);
+ n->face_vert_indices = NULL;
+ }
+
+ if (n->bm_orco) {
+ MEM_freeN(n->bm_orco);
+ n->bm_orco = NULL;
+ }
+
+ if (n->bm_ortri) {
+ MEM_freeN(n->bm_ortri);
+ n->bm_ortri = NULL;
+ }
+
+ if (n->bm_unique_verts) {
+ BLI_table_gset_free(n->bm_unique_verts, NULL);
+ n->bm_unique_verts = NULL;
+ }
+
+ if (n->bm_other_verts) {
+ BLI_table_gset_free(n->bm_other_verts, NULL);
+ n->bm_other_verts = NULL;
+ }
+
+ if (n->bm_faces) {
+ BLI_table_gset_free(n->bm_faces, NULL);
+ n->bm_faces = NULL;
+ }
+
+#ifdef PROXY_ADVANCED
+ BKE_pbvh_free_proxyarray(bvh, n);
+#endif
+ }
+ }
+
+ // compact node array
+ j = 0;
+ for (int i = 0; i < bvh->totnode; i++) {
+ if (!(bvh->nodes[i].flag & PBVH_Delete)) {
+ int i1 = map[bvh->nodes[i].children_offset];
+ int i2 = map[bvh->nodes[i].children_offset + 1];
+
+ if (bvh->nodes[i].children_offset >= bvh->totnode) {
+ printf("bad child node reference %d->%d, totnode: %d\n",
+ i,
+ bvh->nodes[i].children_offset,
+ bvh->totnode);
+ continue;
+ }
+
+ if (bvh->nodes[i].children_offset && i2 != i1 + 1) {
+ printf(" pbvh corruption during node join %d %d\n", i1, i2);
+ }
+
+ bvh->nodes[j] = bvh->nodes[i];
+ bvh->nodes[j].children_offset = i1;
+
+ j++;
+ }
+ }
+
+ if (j != totnode) {
+ printf("pbvh error: %s", __func__);
+ }
+
+ if (bvh->totnode != j) {
+ memset(bvh->nodes + j, 0, sizeof(*bvh->nodes) * (bvh->totnode - j));
+ bvh->node_mem_count = j;
+ }
+
+ bvh->totnode = j;
+
+ BMVert *v;
+
+ // set vert/face node indices again
+ for (int i = 0; i < bvh->totnode; i++) {
+ PBVHNode *n = bvh->nodes + i;
+
+ if (!(n->flag & PBVH_Leaf)) {
+ continue;
+ }
+
+ if (!n->bm_unique_verts) {
+ printf("ERROR!\n");
+ n->bm_unique_verts = BLI_table_gset_new("bleh");
+ n->bm_other_verts = BLI_table_gset_new("bleh");
+ n->bm_faces = BLI_table_gset_new("bleh");
+ }
+
+ BMVert *v;
+
+ TGSET_ITER (v, n->bm_unique_verts) {
+ BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, i);
+ }
+ TGSET_ITER_END
+
+ BMFace *f;
+
+ TGSET_ITER (f, n->bm_faces) {
+ BM_ELEM_CD_SET_INT(f, bvh->cd_face_node_offset, i);
+ }
+ TGSET_ITER_END
+ }
+
+ BMVert **scratch = NULL;
+ BLI_array_declare(scratch);
+
+ for (int i = 0; i < bvh->totnode; i++) {
+ PBVHNode *n = bvh->nodes + i;
+
+ if (!(n->flag & PBVH_Leaf)) {
+ continue;
+ }
+
+ BLI_array_clear(scratch);
+ BMVert *v;
+
+ TGSET_ITER (v, n->bm_other_verts) {
+ int ni = BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset);
+ if (ni == DYNTOPO_NODE_NONE) {
+ BLI_array_append(scratch, v);
+ }
+ // BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, i);
+ }
+ TGSET_ITER_END
+
+ int slen = BLI_array_len(scratch);
+ for (int j = 0; j < slen; j++) {
+ BMVert *v = scratch[j];
+
+ BLI_table_gset_remove(n->bm_other_verts, v, NULL);
+ BLI_table_gset_add(n->bm_unique_verts, v);
+ BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, i);
+ }
+ }
+
+ BLI_array_free(scratch);
+ MEM_freeN(map);
+}
+
void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh)
{
+ check_heap();
+ int totnode = pbvh->totnode;
+
+ pbvh_bmesh_join_nodes(pbvh);
+
+ check_heap();
+
for (int i = 0; i < pbvh->totnode; i++) {
- PBVHNode *n = &pbvh->nodes[i];
+ PBVHNode *n = pbvh->nodes + i;
+
+ if (totnode != pbvh->totnode) {
+#ifdef PROXY_ADVANCED
+ BKE_pbvh_free_proxyarray(pbvh, n);
+#endif
+ }
+
if (n->flag & PBVH_Leaf) {
/* Free orco/ortri data */
pbvh_bmesh_node_drop_orig(n);
@@ -2105,6 +3612,8 @@ void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh)
pbvh_bmesh_node_limit_ensure(pbvh, i);
}
}
+
+ BKE_pbvh_update_bounds(pbvh, (PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw));
}
void BKE_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size)
@@ -2118,17 +3627,17 @@ void BKE_pbvh_node_mark_topology_update(PBVHNode *node)
node->flag |= PBVH_UpdateTopology;
}
-GSet *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node)
+TableGSet *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node)
{
return node->bm_unique_verts;
}
-GSet *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node)
+TableGSet *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node)
{
return node->bm_other_verts;
}
-struct GSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node)
+struct TableGSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node)
{
return node->bm_faces;
}
@@ -2189,23 +3698,23 @@ static void print_flag_factors(int flag)
static void pbvh_bmesh_verify(PBVH *pbvh)
{
/* build list of faces & verts to lookup */
- GSet *faces_all = BLI_gset_ptr_new_ex(__func__, pbvh->bm->totface);
+ GSet *faces_all = BLI_table_gset_new_ex(__func__, pbvh->bm->totface);
BMIter iter;
{
BMFace *f;
BM_ITER_MESH (f, &iter, pbvh->bm, BM_FACES_OF_MESH) {
BLI_assert(BM_ELEM_CD_GET_INT(f, pbvh->cd_face_node_offset) != DYNTOPO_NODE_NONE);
- BLI_gset_insert(faces_all, f);
+ BLI_table_gset_insert(faces_all, f);
}
}
- GSet *verts_all = BLI_gset_ptr_new_ex(__func__, pbvh->bm->totvert);
+ GSet *verts_all = BLI_table_gset_new_ex(__func__, pbvh->bm->totvert);
{
BMVert *v;
BM_ITER_MESH (v, &iter, pbvh->bm, BM_VERTS_OF_MESH) {
if (BM_ELEM_CD_GET_INT(v, pbvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
- BLI_gset_insert(verts_all, v);
+ BLI_table_gset_insert(verts_all, v);
}
}
}
@@ -2215,12 +3724,12 @@ static void pbvh_bmesh_verify(PBVH *pbvh)
int totface = 0, totvert = 0;
for (int i = 0; i < pbvh->totnode; i++) {
PBVHNode *n = &pbvh->nodes[i];
- totface += n->bm_faces ? BLI_gset_len(n->bm_faces) : 0;
- totvert += n->bm_unique_verts ? BLI_gset_len(n->bm_unique_verts) : 0;
+ totface += n->bm_faces ? BLI_table_gset_len(n->bm_faces) : 0;
+ totvert += n->bm_unique_verts ? BLI_table_gset_len(n->bm_unique_verts) : 0;
}
- BLI_assert(totface == BLI_gset_len(faces_all));
- BLI_assert(totvert == BLI_gset_len(verts_all));
+ BLI_assert(totface == BLI_table_gset_len(faces_all));
+ BLI_assert(totvert == BLI_table_gset_len(verts_all));
}
{
@@ -2234,23 +3743,24 @@ static void pbvh_bmesh_verify(PBVH *pbvh)
BLI_assert(n->flag & PBVH_Leaf);
/* Check that the face's node knows it owns the face */
- BLI_assert(BLI_gset_haskey(n->bm_faces, f));
+ BLI_assert(BLI_table_gset_haskey(n->bm_faces, f));
/* Check the face's vertices... */
BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) {
PBVHNode *nv;
/* Check that the vertex is in the node */
- BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v) ^ BLI_gset_haskey(n->bm_other_verts, v));
+ BLI_assert(BLI_table_gset_haskey(n->bm_unique_verts, v) ^
+ BLI_table_gset_haskey(n->bm_other_verts, v));
/* Check that the vertex has a node owner */
nv = pbvh_bmesh_node_lookup(pbvh, v);
/* Check that the vertex's node knows it owns the vert */
- BLI_assert(BLI_gset_haskey(nv->bm_unique_verts, v));
+ BLI_assert(BLI_table_gset_haskey(nv->bm_unique_verts, v));
/* Check that the vertex isn't duplicated as an 'other' vert */
- BLI_assert(!BLI_gset_haskey(nv->bm_other_verts, v));
+ BLI_assert(!BLI_table_gset_haskey(nv->bm_other_verts, v));
}
}
}
@@ -2270,10 +3780,10 @@ static void pbvh_bmesh_verify(PBVH *pbvh)
BLI_assert(n->flag & PBVH_Leaf);
/* Check that the vert's node knows it owns the vert */
- BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v));
+ BLI_assert(BLI_table_gset_haskey(n->bm_unique_verts, v));
/* Check that the vertex isn't duplicated as an 'other' vert */
- BLI_assert(!BLI_gset_haskey(n->bm_other_verts, v));
+ BLI_assert(!BLI_table_gset_haskey(n->bm_other_verts, v));
/* Check that the vert's node also contains one of the vert's
* adjacent faces */
@@ -2294,7 +3804,7 @@ static void pbvh_bmesh_verify(PBVH *pbvh)
for (int i = 0; i < pbvh->totnode; i++) {
PBVHNode *n_other = &pbvh->nodes[i];
if ((n != n_other) && (n_other->bm_unique_verts)) {
- BLI_assert(!BLI_gset_haskey(n_other->bm_unique_verts, v));
+ BLI_assert(!BLI_table_gset_haskey(n_other->bm_unique_verts, v));
}
}
# endif
@@ -2308,7 +3818,7 @@ static void pbvh_bmesh_verify(PBVH *pbvh)
bool has_unique = false;
for (int i = 0; i < pbvh->totnode; i++) {
PBVHNode *n = &pbvh->nodes[i];
- if ((n->bm_unique_verts != NULL) && BLI_gset_haskey(n->bm_unique_verts, vi)) {
+ if ((n->bm_unique_verts != NULL) && BLI_table_gset_haskey(n->bm_unique_verts, vi)) {
has_unique = true;
}
}
@@ -2330,28 +3840,202 @@ static void pbvh_bmesh_verify(PBVH *pbvh)
BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
PBVHNode *n_other = pbvh_bmesh_node_lookup(pbvh, f);
BLI_assert(n == n_other);
- BLI_assert(BLI_gset_haskey(faces_all, f));
+ BLI_assert(BLI_table_gset_haskey(faces_all, f));
}
GSET_ITER (gs_iter, n->bm_unique_verts) {
BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
PBVHNode *n_other = pbvh_bmesh_node_lookup(pbvh, v);
- BLI_assert(!BLI_gset_haskey(n->bm_other_verts, v));
+ BLI_assert(!BLI_table_gset_haskey(n->bm_other_verts, v));
BLI_assert(n == n_other);
- BLI_assert(BLI_gset_haskey(verts_all, v));
+ BLI_assert(BLI_table_gset_haskey(verts_all, v));
}
GSET_ITER (gs_iter, n->bm_other_verts) {
BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
/* this happens sometimes and seems harmless */
// BLI_assert(!BM_vert_face_check(v));
- BLI_assert(BLI_gset_haskey(verts_all, v));
+ BLI_assert(BLI_table_gset_haskey(verts_all, v));
}
}
}
- BLI_gset_free(faces_all, NULL);
- BLI_gset_free(verts_all, NULL);
+ BLI_table_gset_free(faces_all, NULL);
+ BLI_table_gset_free(verts_all, NULL);
}
#endif
+
+void BKE_pbvh_update_offsets(PBVH *pbvh,
+ const int cd_vert_node_offset,
+ const int cd_face_node_offset,
+ const int cd_origco_offset,
+ const int cd_origno_offset,
+ const int cd_origvcol_offset)
+{
+ pbvh->cd_face_node_offset = cd_face_node_offset;
+ pbvh->cd_vert_node_offset = cd_vert_node_offset;
+ pbvh->cd_vert_mask_offset = CustomData_get_offset(&pbvh->bm->vdata, CD_PAINT_MASK);
+ pbvh->cd_origco_offset = cd_origco_offset;
+ pbvh->cd_origno_offset = cd_origno_offset;
+ pbvh->cd_origvcol_offset = cd_origvcol_offset;
+ pbvh->cd_faceset_offset = CustomData_get_offset(&pbvh->bm->pdata, CD_SCULPT_FACE_SETS);
+}
+
+static void scan_edge_split(BMesh *bm, BMEdge **edges, int totedge)
+{
+ BMFace **faces = NULL;
+ BMEdge **newedges = NULL;
+ BMVert **newverts = NULL;
+ BMVert **fmap = NULL; // newverts that maps to faces
+ int *emap = NULL;
+
+ BLI_array_declare(faces);
+ BLI_array_declare(newedges);
+ BLI_array_declare(newverts);
+ BLI_array_declare(fmap);
+ BLI_array_declare(emap);
+
+ // remove e from radial list of e->v2
+ for (int i = 0; i < totedge; i++) {
+ BMEdge *e = edges[i];
+
+ BMDiskLink *prev;
+ BMDiskLink *next;
+
+ if (e->v2_disk_link.prev->v1 == e->v2) {
+ prev = &e->v2_disk_link.prev->v1_disk_link;
+ }
+ else {
+ prev = &e->v2_disk_link.prev->v2_disk_link;
+ }
+
+ if (e->v2_disk_link.next->v1 == e->v2) {
+ next = &e->v2_disk_link.next->v1_disk_link;
+ }
+ else {
+ next = &e->v2_disk_link.next->v2_disk_link;
+ }
+
+ prev->next = e->v2_disk_link.next;
+ next->prev = e->v2_disk_link.prev;
+ }
+
+ for (int i = 0; i < totedge; i++) {
+ BMEdge *e = edges[i];
+
+ BMVert *v2 = BLI_mempool_alloc(bm->vpool);
+ memset(v2, 0, sizeof(*v2));
+ v2->head.data = BLI_mempool_alloc(bm->vdata.pool);
+
+ BLI_array_append(newverts, v2);
+
+ BMEdge *e2 = BLI_mempool_alloc(bm->epool);
+ BLI_array_append(newedges, e2);
+
+ memset(e2, 0, sizeof(*e2));
+ if (bm->edata.pool) {
+ e2->head.data = BLI_mempool_alloc(bm->edata.pool);
+ }
+
+ BMLoop *l = e->l;
+
+ if (!l) {
+ continue;
+ }
+
+ do {
+ BLI_array_append(faces, l->f);
+ BMFace *f2 = BLI_mempool_alloc(bm->fpool);
+
+ BLI_array_append(faces, l->f);
+ BLI_array_append(fmap, v2);
+ BLI_array_append(emap, i);
+
+ BLI_array_append(faces, f2);
+ BLI_array_append(fmap, v2);
+ BLI_array_append(emap, i);
+
+ memset(f2, 0, sizeof(*f2));
+ f2->head.data = BLI_mempool_alloc(bm->ldata.pool);
+
+ BMLoop *prev = NULL;
+ BMLoop *l2;
+
+ for (int j = 0; j < 3; j++) {
+ l2 = BLI_mempool_alloc(bm->lpool);
+ memset(l2, 0, sizeof(*l2));
+ l2->head.data = BLI_mempool_alloc(bm->ldata.pool);
+
+ l2->prev = prev;
+
+ if (prev) {
+ prev->next = l2;
+ }
+ else {
+ f2->l_first = l2;
+ }
+ }
+
+ f2->l_first->prev = l2;
+ l2->next = f2->l_first;
+
+ BLI_array_append(faces, f2);
+ l = l->radial_next;
+ } while (l != e->l);
+ }
+
+ for (int i = 0; i < BLI_array_len(newedges); i++) {
+ BMEdge *e1 = edges[i];
+ BMEdge *e2 = newedges[i];
+ BMVert *v = newverts[i];
+
+ add_v3_v3v3(v->co, e1->v1->co, e1->v2->co);
+ mul_v3_fl(v->co, 0.5f);
+
+ e2->v1 = v;
+ e2->v2 = e1->v2;
+ e1->v2 = v;
+
+ v->e = e1;
+
+ e1->v2_disk_link.next = e1->v2_disk_link.prev = e2;
+ e2->v1_disk_link.next = e2->v1_disk_link.prev = e1;
+ }
+
+ for (int i = 0; i < BLI_array_len(faces); i += 2) {
+ BMFace *f1 = faces[i], *f2 = faces[i + 1];
+ BMEdge *e1 = edges[emap[i]];
+ BMEdge *e2 = newedges[emap[i]];
+ BMVert *nv = fmap[i];
+
+ // make sure first loop points to e1->v1
+ BMLoop *l = f1->l_first;
+ do {
+ if (l->v == e1->v1) {
+ break;
+ }
+ l = l->next;
+ } while (l != f1->l_first);
+
+ f1->l_first = l;
+
+ BMLoop *l2 = f2->l_first;
+
+ l2->f = l2->next->f = l2->prev->f = f2;
+ l2->v = nv;
+ l2->next->v = l->next->v;
+ l2->prev->v = l->prev->v;
+ l2->e = e2;
+ l2->next->e = l->next->e;
+ l2->prev->e = l->prev->e;
+
+ l->next->v = nv;
+ l->next->e = e2;
+ }
+
+ BLI_array_free(newedges);
+ BLI_array_free(newverts);
+ BLI_array_free(faces);
+ BLI_array_free(fmap);
+}
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index 63bc8753fc7..8a0253facc8 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -16,6 +16,8 @@
#pragma once
+#include "BLI_ghash.h"
+
/** \file
* \ingroup bli
*/
@@ -43,6 +45,7 @@ struct PBVHNode {
/* For internal nodes, the offset of the children in the PBVH
* 'nodes' array. */
int children_offset;
+ int subtree_tottri;
/* Pointer into the PBVH prim_indices array and the number of
* primitives used by this leaf node.
@@ -86,7 +89,7 @@ struct PBVHNode {
/* Indicates whether this node is a leaf or not; also used for
* marking various updates that need to be applied. */
- PBVHNodeFlags flag : 16;
+ PBVHNodeFlags flag : 32;
/* Used for raycasting: how close bb is to the ray point. */
float tmin;
@@ -98,15 +101,18 @@ struct PBVHNode {
PBVHProxyNode *proxies;
/* Dyntopo */
- GSet *bm_faces;
- GSet *bm_unique_verts;
- GSet *bm_other_verts;
+ TableGSet *bm_faces;
+ TableGSet *bm_unique_verts;
+ TableGSet *bm_other_verts;
float (*bm_orco)[3];
int (*bm_ortri)[3];
int bm_tot_ortri;
/* Used to store the brush color during a stroke and composite it over the original color */
PBVHColorBufferNode color_buffer;
+#ifdef PROXY_ADVANCED
+ ProxyVertArray proxyverts;
+#endif
};
typedef enum {
@@ -170,12 +176,20 @@ struct PBVH {
float bm_min_edge_len;
int cd_vert_node_offset;
int cd_face_node_offset;
+ int cd_vert_mask_offset;
+ int cd_vcol_offset;
+ int cd_origco_offset;
+ int cd_origno_offset;
+ int cd_origvcol_offset;
+ int cd_faceset_offset;
float planes[6][4];
int num_planes;
struct BMLog *bm_log;
struct SubdivCCG *subdiv_ccg;
+
+ bool flat_vcol_shading;
};
/* pbvh.c */
@@ -224,7 +238,8 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node,
struct IsectRayPrecalc *isect_precalc,
float *dist,
bool use_original,
- int *r_active_vertex_index,
+ SculptVertRef *r_active_vertex_index,
+ SculptFaceRef *r_active_face_index,
float *r_face_normal);
bool pbvh_bmesh_node_nearest_to_ray(PBVHNode *node,
const float ray_start[3],
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 3633dff8690..d77541924a7 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -2565,6 +2565,7 @@ static void prepare_mesh_for_viewport_render(Main *bmain, const ViewLayer *view_
if (check_rendered_viewport_visible(bmain)) {
BMesh *bm = mesh->edit_mesh->bm;
BM_mesh_bm_to_me(bmain,
+ NULL,
bm,
mesh,
(&(struct BMeshToMeshParams){
diff --git a/source/blender/blenkernel/intern/subdiv_displacement_multires.c b/source/blender/blenkernel/intern/subdiv_displacement_multires.c
index 0fb08880dd5..344162a6eb1 100644
--- a/source/blender/blenkernel/intern/subdiv_displacement_multires.c
+++ b/source/blender/blenkernel/intern/subdiv_displacement_multires.c
@@ -360,8 +360,9 @@ static void eval_displacement(SubdivDisplacement *displacement,
BKE_multires_construct_tangent_matrix(tangent_matrix, dPdu, dPdv, corner_of_quad);
mul_v3_m3v3(r_D, tangent_matrix, tangent_D);
/* For the boundary points of grid average two (or all) neighbor grids. */
- const int corner = displacement_get_face_corner(data, ptex_face_index, u, v);
- average_displacement(displacement, average_with, ptex_face_index, corner, grid_u, grid_v, r_D);
+ //XXX
+ //const int corner = displacement_get_face_corner(data, ptex_face_index, u, v);
+ //average_displacement(displacement, average_with, ptex_face_index, corner, grid_u, grid_v, r_D);
}
static void free_displacement(SubdivDisplacement *displacement)
diff --git a/source/blender/blenkernel/intern/subdiv_eval.c b/source/blender/blenkernel/intern/subdiv_eval.c
index 201d308e096..b858c847a68 100644
--- a/source/blender/blenkernel/intern/subdiv_eval.c
+++ b/source/blender/blenkernel/intern/subdiv_eval.c
@@ -174,6 +174,13 @@ void BKE_subdiv_eval_limit_point(
BKE_subdiv_eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, r_P, NULL, NULL);
}
+#if 0
+static bool close_zero(float c[3]) {
+ const float eps = 0.00001;
+ return fabs(c[0]) < eps && fabs(c[1]) < eps && fabs(c[2]) < eps;
+}
+#endif
+
void BKE_subdiv_eval_limit_point_and_derivatives(Subdiv *subdiv,
const int ptex_face_index,
const float u,
@@ -196,6 +203,7 @@ void BKE_subdiv_eval_limit_point_and_derivatives(Subdiv *subdiv,
* that giving totally unusable derivatives. */
if (r_dPdu != NULL && r_dPdv != NULL) {
+ //if ((close_zero(r_dPdu) || close_zero(r_dPdv)) || equals_v3v3(r_dPdu, r_dPdv)) {
if ((is_zero_v3(r_dPdu) || is_zero_v3(r_dPdv)) || equals_v3v3(r_dPdu, r_dPdv)) {
subdiv->evaluator->evaluateLimit(subdiv->evaluator,
ptex_face_index,
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
index bc517f81955..fcf9ca61200 100644
--- a/source/blender/blenlib/BLI_ghash.h
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -188,6 +188,49 @@ BLI_INLINE bool BLI_ghashIterator_done(GHashIterator *ghi)
typedef struct GSet GSet;
+typedef struct TableGSet {
+ struct GHash *ptr_to_idx;
+ void **elems;
+ int size, length;
+ int cur;
+} TableGSet;
+
+TableGSet *BLI_table_gset_new(const char *info);
+TableGSet *BLI_table_gset_new_ex(const char *info, int size);
+void BLI_table_gset_free(TableGSet *ts, GHashKeyFreeFP freefp);
+void BLI_table_gset_insert(TableGSet *ts, void *elem);
+bool BLI_table_gset_add(TableGSet *ts, void *elem);
+void BLI_table_gset_remove(TableGSet *ts, void *elem, GHashKeyFreeFP freefp);
+bool BLI_table_gset_haskey(TableGSet *ts, void *elem);
+
+int BLI_table_gset_len(TableGSet *ts);
+
+#define TGSET_ITER(v, ts) \
+ { \
+ int _i1; \
+ for (_i1 = 0; _i1 < (ts)->cur; _i1++) { \
+ if (!(ts)->elems[_i1]) \
+ continue; \
+ v = (ts)->elems[_i1];
+
+#define TGSET_ITER_END \
+ } \
+ }
+
+#define TGSET_ITER_INDEX(v, ts, index) \
+ { \
+ int _i1; \
+ index = -1; \
+ for (_i1 = 0; _i1 < (ts)->cur; _i1++) { \
+ if (!(ts)->elems[_i1]) \
+ continue; \
+ v = (ts)->elems[_i1]; \
+ index++;
+
+#define TGSET_ITER_INDEX_END \
+ } \
+ } \
+
typedef GHashHashFP GSetHashFP;
typedef GHashCmpFP GSetCmpFP;
typedef GHashKeyFreeFP GSetKeyFreeFP;
diff --git a/source/blender/blenlib/intern/BLI_ghash_utils.c b/source/blender/blenlib/intern/BLI_ghash_utils.c
index 83f64043cd0..b64659fca3f 100644
--- a/source/blender/blenlib/intern/BLI_ghash_utils.c
+++ b/source/blender/blenlib/intern/BLI_ghash_utils.c
@@ -288,4 +288,125 @@ GSet *BLI_gset_int_new(const char *info)
return BLI_gset_int_new_ex(info, 0);
}
+
+TableGSet *BLI_table_gset_new(const char *info)
+{
+ TableGSet *ts = MEM_callocN(sizeof(TableGSet), info);
+
+ ts->ptr_to_idx = BLI_ghash_ptr_new(info);
+
+ return ts;
+}
+
+TableGSet *BLI_table_gset_new_ex(const char *info, int size)
+{
+ TableGSet *ts = MEM_callocN(sizeof(TableGSet), info);
+
+ ts->ptr_to_idx = BLI_ghash_ptr_new_ex(info, size);
+ if (size) {
+ ts->elems = MEM_callocN(sizeof(void*)*size, info);
+ ts->size = size;
+ ts->length = 0;
+ ts->cur = 0;
+ }
+
+ return ts;
+}
+
+void BLI_table_gset_free(TableGSet *ts, GHashKeyFreeFP freefp)
+{
+ if (!ts->ptr_to_idx) {
+ printf("double call to BLI_table_gset_free!\n");
+ return;
+ }
+
+ if (ts->elems) {
+ MEM_freeN(ts->elems);
+ }
+
+ BLI_ghash_free(ts->ptr_to_idx, freefp, NULL);
+ ts->ptr_to_idx = NULL;
+
+ MEM_freeN(ts);
+}
+
+bool BLI_table_gset_add(TableGSet *ts, void *elem)
+{
+ if (BLI_table_gset_haskey(ts, elem)) {
+ return true;
+ }
+
+ BLI_table_gset_insert(ts, elem);
+ return false;
+}
+
+void BLI_table_gset_insert(TableGSet *ts, void *elem)
+{
+ if (ts->cur >= ts->size) {
+ int newsize = (ts->cur + 1);
+ newsize = (newsize << 1) - (newsize >> 1);
+ newsize = MAX2(newsize, 8);
+
+ if (!ts->elems) {
+ ts->elems = (void *)MEM_mallocN(sizeof(void *) * newsize, "ts->elems");
+ }
+ else {
+ ts->elems = (void *)MEM_reallocN(ts->elems, newsize * sizeof(void *));
+ }
+
+ BLI_ghash_clear(ts->ptr_to_idx, NULL, NULL);
+
+ // compact
+ int i = 0, j = 0;
+ for (i = 0; i < ts->cur; i++) {
+ void *elem2 = ts->elems[i];
+
+ if (elem2) {
+ BLI_ghash_insert(ts->ptr_to_idx, elem2, (void *)j);
+ ts->elems[j++] = elem2;
+ }
+ }
+
+ ts->size = newsize;
+ ts->cur = j;
+ }
+
+ BLI_ghash_insert(ts->ptr_to_idx, elem, (void *)ts->cur);
+ ts->elems[ts->cur++] = elem;
+ ts->length++;
+}
+
+void BLI_table_gset_remove(TableGSet *ts, void *elem, GHashKeyFreeFP freefp)
+{
+ if (!elem || !ts) {
+ return;
+ }
+
+ int *idx = (int*)BLI_ghash_lookup_p(ts->ptr_to_idx, elem);
+ if (!idx) {
+ return;
+ }
+
+ int idx2 = *idx;
+
+ BLI_ghash_remove(ts->ptr_to_idx, elem, freefp, NULL);
+
+ if (!ts->elems || ts->elems[idx2] != elem) {
+ return;
+ }
+
+ ts->length--;
+ ts->elems[idx2] = NULL;
+}
+
+bool BLI_table_gset_haskey(TableGSet *ts, void *elem)
+{
+ return BLI_ghash_haskey(ts->ptr_to_idx, elem);
+}
+
+int BLI_table_gset_len(TableGSet *ts)
+{
+ return ts->length;
+}
+
/** \} */
diff --git a/source/blender/blenlib/intern/BLI_mempool.c b/source/blender/blenlib/intern/BLI_mempool.c
index e5868abbe2c..461f867d861 100644
--- a/source/blender/blenlib/intern/BLI_mempool.c
+++ b/source/blender/blenlib/intern/BLI_mempool.c
@@ -37,6 +37,7 @@
#include "BLI_utildefines.h"
#include "BLI_mempool.h" /* own include */
+#include "BLI_asan.h"
#include "MEM_guardedalloc.h"
@@ -223,13 +224,18 @@ static BLI_freenode *mempool_chunk_add(BLI_mempool *pool,
while (j--) {
curnode->next = NODE_STEP_NEXT(curnode);
curnode->freeword = FREEWORD;
- curnode = curnode->next;
+
+ BLI_freenode *next = curnode->next;
+ //BLI_asan_poison(curnode, pool->esize);
+ curnode = next;
}
}
else {
while (j--) {
curnode->next = NODE_STEP_NEXT(curnode);
- curnode = curnode->next;
+ BLI_freenode *next = curnode->next;
+ ////BLI_asan_poison(curnode, pool->esize);
+ curnode = next;
}
}
@@ -250,18 +256,20 @@ static BLI_freenode *mempool_chunk_add(BLI_mempool *pool,
return curnode;
}
-static void mempool_chunk_free(BLI_mempool_chunk *mpchunk)
+static void mempool_chunk_free(BLI_mempool *pool, BLI_mempool_chunk *mpchunk)
{
+ //BLI_asan_unpoison(mpchunk, sizeof(BLI_mempool_chunk) + pool->esize*pool->csize);
+
MEM_freeN(mpchunk);
}
-static void mempool_chunk_free_all(BLI_mempool_chunk *mpchunk)
+static void mempool_chunk_free_all(BLI_mempool *pool, BLI_mempool_chunk *mpchunk)
{
BLI_mempool_chunk *mpchunk_next;
for (; mpchunk; mpchunk = mpchunk_next) {
mpchunk_next = mpchunk->next;
- mempool_chunk_free(mpchunk);
+ mempool_chunk_free(pool, mpchunk);
}
}
@@ -343,6 +351,8 @@ void *BLI_mempool_alloc(BLI_mempool *pool)
free_pop = pool->free;
+ //BLI_asan_unpoison(free_pop, pool->esize);
+
BLI_assert(pool->chunk_tail->next == NULL);
if (pool->flag & BLI_MEMPOOL_ALLOW_ITER) {
@@ -404,7 +414,9 @@ void BLI_mempool_free(BLI_mempool *pool, void *addr)
newhead->freeword = FREEWORD;
}
+
newhead->next = pool->free;
+
pool->free = newhead;
pool->totused--;
@@ -421,7 +433,7 @@ void BLI_mempool_free(BLI_mempool *pool, void *addr)
BLI_mempool_chunk *first;
first = pool->chunks;
- mempool_chunk_free_all(first->next);
+ mempool_chunk_free_all(pool, first->next);
first->next = NULL;
pool->chunk_tail = first;
@@ -439,15 +451,20 @@ void BLI_mempool_free(BLI_mempool *pool, void *addr)
j = pool->pchunk;
while (j--) {
- curnode->next = NODE_STEP_NEXT(curnode);
- curnode = curnode->next;
+ BLI_freenode *next = NODE_STEP_NEXT(curnode);
+ curnode->next = next;
+ //BLI_asan_poison(curnode, pool->esize);
+ curnode = next;
}
curnode = NODE_STEP_PREV(curnode);
curnode->next = NULL; /* terminate the list */
+ // BLI_asan_poison(newhead, pool->esize);
#ifdef WITH_MEM_VALGRIND
VALGRIND_MEMPOOL_FREE(pool, CHUNK_DATA(first));
#endif
+ } else {
+ //BLI_asan_poison(newhead, pool->esize);
}
}
@@ -722,7 +739,7 @@ void BLI_mempool_clear_ex(BLI_mempool *pool, const int totelem_reserve)
do {
mpchunk_next = mpchunk->next;
- mempool_chunk_free(mpchunk);
+ mempool_chunk_free(pool, mpchunk);
} while ((mpchunk = mpchunk_next));
}
@@ -756,7 +773,7 @@ void BLI_mempool_clear(BLI_mempool *pool)
*/
void BLI_mempool_destroy(BLI_mempool *pool)
{
- mempool_chunk_free_all(pool->chunks);
+ mempool_chunk_free_all(pool, pool->chunks);
#ifdef WITH_MEM_VALGRIND
VALGRIND_DESTROY_MEMPOOL(pool);
diff --git a/source/blender/blenlib/intern/task_pool.cc b/source/blender/blenlib/intern/task_pool.cc
index 00ba659a9c8..1c48bcf9af4 100644
--- a/source/blender/blenlib/intern/task_pool.cc
+++ b/source/blender/blenlib/intern/task_pool.cc
@@ -90,7 +90,8 @@ class Task {
other.freedata = nullptr;
}
-#if defined(WITH_TBB) && TBB_INTERFACE_VERSION_MAJOR < 10
+#if (defined(WITH_TBB) && TBB_INTERFACE_VERSION_MAJOR < 10) || \
+ (defined(__clang__) && defined(WIN32))
Task(const Task &other)
: pool(other.pool),
run(other.run),
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index 5c8e9da41c4..f1245a31c70 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -1358,6 +1358,16 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
+ if (!MAIN_VERSION_ATLEAST(bmain, 293, 0)) {
+ for (Brush *br = bmain->brushes.first; br; br = br->id.next) {
+ if (br->sculpt_tool == SCULPT_TOOL_VCOL_BOUNDARY) {
+ if (br->vcol_boundary_exponent == 0.0f) {
+ br->vcol_boundary_exponent = 1.0f;
+ }
+ }
+ }
+ }
+
if (!MAIN_VERSION_ATLEAST(bmain, 292, 5)) {
/* Initialize the opacity of the overlay wireframe */
if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "wireframe_opacity")) {
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index 52efeb1e822..b2b93302512 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -699,6 +699,14 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
brush->sculpt_tool = SCULPT_TOOL_PAINT;
}
+ brush_name = "Color Boundary";
+ brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ if (!brush) {
+ brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
+ id_us_min(&brush->id);
+ brush->sculpt_tool = SCULPT_TOOL_VCOL_BOUNDARY;
+ }
+
brush_name = "Smear";
brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
if (!brush) {
diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h
index c83fc0645c4..f61921cd61c 100644
--- a/source/blender/bmesh/bmesh_class.h
+++ b/source/blender/bmesh/bmesh_class.h
@@ -16,6 +16,8 @@
#pragma once
+#include "DNA_modifier_types.h"
+
/** \file
* \ingroup bmesh
*
@@ -376,6 +378,9 @@ typedef struct BMesh {
* instead of crashing on invalid memory access.
*/
void *py_handle;
+ MultiresModifierData multires; //copy of multires settings
+ bool haveMultiResSettings;
+ int multiresSpace;
} BMesh;
/** #BMHeader.htype (char) */
diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c
index 6857a1f3929..48a19f6f01c 100644
--- a/source/blender/bmesh/intern/bmesh_interp.c
+++ b/source/blender/bmesh/intern/bmesh_interp.c
@@ -28,10 +28,12 @@
#include "DNA_meshdata_types.h"
#include "BLI_alloca.h"
+#include "BLI_array.h"
#include "BLI_linklist.h"
#include "BLI_math.h"
#include "BLI_memarena.h"
#include "BLI_task.h"
+#include "BLI_utildefines.h"
#include "BKE_customdata.h"
#include "BKE_multires.h"
@@ -314,17 +316,52 @@ static bool quad_co(const float v1[3],
/* rotate */
poly_rotate_plane(n, projverts, 5);
+ float projverts2[4][3];
+
/* subtract origin */
for (i = 0; i < 4; i++) {
sub_v2_v2(projverts[i], projverts[4]);
+
+ copy_v3_v3(projverts2[i], projverts[i]);
}
- if (!isect_point_quad_v2(origin, projverts[0], projverts[1], projverts[2], projverts[3])) {
+ // expand quad a bit
+#if 0
+ float eps = FLT_EPSILON * 40000;
+ float c[3];
+
+ mid_v3_v3v3v3v3(c, projverts[0], projverts[1], projverts[2], projverts[3]);
+
+ sub_v3_v3(projverts2[0], c);
+ sub_v3_v3(projverts2[1], c);
+ sub_v3_v3(projverts2[2], c);
+ sub_v3_v3(projverts2[3], c);
+ mul_v3_fl(projverts2[0], 1.0f + eps);
+ mul_v3_fl(projverts2[1], 1.0f + eps);
+ mul_v3_fl(projverts2[2], 1.0f + eps);
+ mul_v3_fl(projverts2[3], 1.0f + eps);
+ add_v3_v3(projverts2[0], c);
+ add_v3_v3(projverts2[1], c);
+ add_v3_v3(projverts2[2], c);
+ add_v3_v3(projverts2[3], c);
+#endif
+
+ if (!isect_point_quad_v2(origin, projverts2[0], projverts2[1], projverts2[2], projverts2[3])) {
return false;
}
resolve_quad_uv_v2(r_uv, origin, projverts[0], projverts[3], projverts[2], projverts[1]);
+#if 0
+ float eps2 = FLT_EPSILON * 4000;
+ if (r_uv[0] < -eps2 || r_uv[1] < -eps2 || r_uv[0] > 1.0 + eps2 || r_uv[1] > 1.0 + eps2) {
+ return false;
+ }
+#endif
+
+ CLAMP(r_uv[0], 0.0f, 0.99999f);
+ CLAMP(r_uv[1], 0.0f, 0.99999f);
+
return true;
}
@@ -357,8 +394,7 @@ static bool mdisp_in_mdispquad(BMLoop *l_src,
float r_axis_y[3],
float r_uv[2])
{
- float v1[3], v2[3], c[3], v3[3], v4[3], e1[3], e2[3];
- float eps = FLT_EPSILON * 4000;
+ float v1[3], v2[3], v3[3], v4[3], e1[3], e2[3];
if (is_zero_v3(l_src->v->no)) {
BM_vert_normal_update_all(l_src->v);
@@ -370,6 +406,8 @@ static bool mdisp_in_mdispquad(BMLoop *l_src,
compute_mdisp_quad(l_dst, l_dst_f_center, v1, v2, v3, v4, e1, e2);
/* expand quad a bit */
+ float c[3];
+ float eps = FLT_EPSILON * 400;
mid_v3_v3v3v3v3(c, v1, v2, v3, v4);
sub_v3_v3(v1, c);
@@ -451,8 +489,10 @@ typedef struct BMLoopInterpMultiresData {
BMLoop *l_src_first;
int cd_loop_mdisp_offset;
+ int space;
MDisps *md_dst;
const float *f_src_center;
+ const float *f_dst_center;
float *axis_x, *axis_y;
float *v1, *v4;
@@ -471,6 +511,7 @@ static void loop_interp_multires_cb(void *__restrict userdata,
BMLoop *l_first = data->l_src_first;
BMLoop *l_dst = data->l_dst;
const int cd_loop_mdisp_offset = data->cd_loop_mdisp_offset;
+ int space = data->space;
MDisps *md_dst = data->md_dst;
const float *f_src_center = data->f_src_center;
@@ -485,6 +526,19 @@ static void loop_interp_multires_cb(void *__restrict userdata,
const int res = data->res;
const float d = data->d;
+ float quad[4][3];
+
+ float n1[3], n2[3];
+ normal_tri_v3(n1, l_dst->v->co, l_dst->next->v->co, data->f_dst_center);
+
+ if (space == MULTIRES_SPACE_ABSOLUTE) {
+ BMLoop *l = l_dst;
+
+ copy_v3_v3(quad[0], data->f_dst_center);
+ interp_v3_v3v3(quad[1], l->v->co, l->next->v->co, 0.5);
+ copy_v3_v3(quad[2], l->v->co);
+ interp_v3_v3v3(quad[3], l->v->co, l->prev->v->co, 0.5);
+ }
float x = d * ix, y;
int iy;
@@ -496,24 +550,71 @@ static void loop_interp_multires_cb(void *__restrict userdata,
madd_v3_v3v3fl(co2, v4, e2, y);
interp_v3_v3v3(co, co1, co2, x);
+ float sum[3];
+ int tot = 0;
+ zero_v3(sum);
+ float mindis = 1e17;
+
+ float baseco[3];
+ if (space == MULTIRES_SPACE_ABSOLUTE) {
+ interp_bilinear_quad_v3(quad, x, y, baseco);
+ }
+
do {
MDisps *md_src;
float src_axis_x[3], src_axis_y[3];
float uv[2];
+ normal_tri_v3(n2, l_iter->v->co, l_iter->next->v->co, data->f_src_center);
+ float th = dot_v3v3(n1, n2);
+ if (th < 0.0f) {
+ negate_v3(n2);
+ }
+
+ th = acos(dot_v3v3(n1, n2) * 0.999999f);
+ if (th > M_PI * 0.1) {
+ continue;
+ }
+
md_src = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_mdisp_offset);
if (mdisp_in_mdispquad(l_dst, l_iter, f_src_center, co, res, src_axis_x, src_axis_y, uv)) {
- old_mdisps_bilinear(md_dst->disps[iy * res + ix], md_src->disps, res, uv[0], uv[1]);
- bm_loop_flip_disp(src_axis_x, src_axis_y, axis_x, axis_y, md_dst->disps[iy * res + ix]);
+ float disp[3];
+ copy_v3_v3(disp, md_dst->disps[iy * res + ix]);
+
+ old_mdisps_bilinear(disp, md_src->disps, res, uv[0], uv[1]);
- break;
+ if (space == MULTIRES_SPACE_TANGENT) {
+ bm_loop_flip_disp(src_axis_x, src_axis_y, axis_x, axis_y, disp);
+ }
+
+ float l = len_v3v3(disp, baseco);
+ if (l < mindis) {
+ mindis = l;
+ // tot++;
+ // copy_v3_v3(sum, disp);
+ }
+ add_v3_v3(sum, disp);
+ tot++;
+ // break;
}
} while ((l_iter = l_iter->next) != l_first);
+
+ if (tot) {
+ mul_v3_fl(sum, 1.0 / (float)tot);
+ copy_v3_v3(md_dst->disps[iy * res + ix], sum);
+ }
+ else {
+ // printf("failed to set disp: %f %f\n", x, y);
+ if (space == MULTIRES_SPACE_ABSOLUTE) {
+ // copy_v3_v3(md_dst->disps[iy * res + ix], baseco);
+ // copy_v3_v3(md_dst->disps[iy * res + ix], baseco);
+ }
+ }
}
}
-void BM_loop_interp_multires_ex(BMesh *UNUSED(bm),
+void BM_loop_interp_multires_ex(BMesh *bm,
BMLoop *l_dst,
const BMFace *f_src,
const float f_dst_center[3],
@@ -555,7 +656,9 @@ void BM_loop_interp_multires_ex(BMesh *UNUSED(bm),
.cd_loop_mdisp_offset = cd_loop_mdisp_offset,
.md_dst = md_dst,
.f_src_center = f_src_center,
+ .f_dst_center = f_dst_center,
.axis_x = axis_x,
+ .space = bm->multiresSpace,
.axis_y = axis_y,
.v1 = v1,
.v4 = v4,
@@ -601,6 +704,8 @@ void BM_face_interp_multires_ex(BMesh *bm,
BM_loop_interp_multires_ex(
bm, l_iter, f_src, f_dst_center, f_src_center, cd_loop_mdisp_offset);
} while ((l_iter = l_iter->next) != l_first);
+
+ BM_face_multires_bounds_smooth(bm, f_dst);
}
void BM_face_interp_multires(BMesh *bm, BMFace *f_dst, const BMFace *f_src)
@@ -618,58 +723,277 @@ void BM_face_interp_multires(BMesh *bm, BMFace *f_dst, const BMFace *f_src)
}
}
-/**
- * smooths boundaries between multires grids,
- * including some borders in adjacent faces
- */
-void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f)
+// smooth with weight falloff towards center of grids
+static void bm_multires_smooth(BMesh *bm, BMFace *f, bool no_boundary)
{
const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
- BMLoop *l;
- BMIter liter;
+ float(*orig)[3] = NULL;
+ BLI_array_staticdeclare(orig, 256 * 256);
- if (cd_loop_mdisp_offset == -1) {
+ if (cd_loop_mdisp_offset < 0) {
return;
}
- BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- MDisps *mdp = BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_mdisp_offset);
- MDisps *mdl = BM_ELEM_CD_GET_VOID_P(l, cd_loop_mdisp_offset);
- MDisps *mdn = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_mdisp_offset);
- float co1[3];
- int sides;
- int y;
+ float cent[3];
+ zero_v3(cent);
- /**
- * mdisps is a grid of displacements, ordered thus:
- * <pre>
- * v4/next
- * |
- * | v1/cent-----mid2 ---> x
- * | | |
- * | | |
- * v2/prev---mid1-----v3/cur
- * |
- * V
- * y
- * </pre>
- */
+ int ctot = 0;
+ BMLoop *cl = f->l_first;
+ do {
+ add_v3_v3(cent, cl->v->co);
+ cl = cl->next;
+ ctot++;
+ } while (cl != f->l_first);
+ mul_v3_fl(cent, 1.0f / (float)ctot);
+
+ const int offs[][2] = {
+ {0, 0},
+ // {-1, -1},
+ {-1, 0},
+ // {-1, 1},
+ {0, 1},
+ // {1, 1},
+ {1, 0},
+ // {1, -1},
+ {0, -1},
+ };
- sides = (int)sqrt(mdp->totdisp);
- for (y = 0; y < sides; y++) {
- mid_v3_v3v3(co1, mdn->disps[y * sides], mdl->disps[y]);
+ int totoff = sizeof(offs) / sizeof(*offs);
+
+#ifndef ABS
+# define ABS(a) ((a) < 0 ? -(a) : (a))
+#endif
+
+ // int space = bm->multiresSpace;
+ BMLoop *l = f->l_first;
+ do {
+ MDisps *md = BM_ELEM_CD_GET_VOID_P(l, cd_loop_mdisp_offset);
+ if (!md->disps)
+ continue;
- copy_v3_v3(mdn->disps[y * sides], co1);
- copy_v3_v3(mdl->disps[y], co1);
+ int res = (int)floor(sqrt((double)md->totdisp) + 0.000001);
+
+ int start = no_boundary ? 1 : 0;
+ int end = no_boundary ? res - 1 : res;
+ float df = 1.0f / (float)(res - 1);
+ float u = 0.0;
+
+ BLI_array_clear(orig);
+ BLI_array_reserve(orig, md->totdisp * 3);
+ memcpy(orig, md->disps, sizeof(float) * 3 * md->totdisp);
+
+ for (int x = start; x < end; x++, u += df) {
+ float v = 0.0;
+
+ for (int y = start; y < end; y++, v += df) {
+ float co[3];
+ float tot = 0.0f;
+
+ zero_v3(co);
+
+ int idx1 = y * res + x;
+
+ for (int oi = 0; oi < totoff; oi++) {
+ int ox = x + offs[oi][0];
+ int oy = y + offs[oi][1];
+ MDisps *md2 = md;
+
+ if (1 && (ox < 0 || oy < 0 || ox >= res || oy >= res)) {
+ BMLoop *l2 = NULL;
+ BMLoop *ls = l;
+
+ if (ox < 0 && oy < 0) {
+ l2 = ls->next->next;
+ ox = ABS(ox);
+ oy = ABS(oy);
+ }
+ else if (ox < 0 && oy >= 0 && oy < res) {
+ l2 = ls->prev;
+ int t = oy;
+
+ oy = -ox;
+ ox = t;
+ }
+ else if (oy < 0 && ox >= 0 && ox < res) {
+ l2 = ls->next;
+ int t = oy;
+
+ oy = ox;
+ ox = -t;
+ }
+ else if (ox >= res && oy >= 0 && oy < res) {
+ l2 = ls->radial_next->next;
+
+ if (ls->v == l2->v) {
+ int t = oy;
+
+ oy = 2 * res - ox - 1;
+ ox = t;
+ }
+ else {
+ l2 = l2->prev;
+ ox = res - ox;
+ }
+
+ // XXX disables this branch
+ // ox = oy = -1;
+ }
+ else if (oy >= res && ox >= 0 && ox < res) {
+ l2 = ls->prev->radial_next;
+ if (l2->v == ls->v) {
+ int t = ox;
+
+ ox = 2 * res - oy - 1;
+ oy = t;
+ }
+ else {
+ l2 = l2->next;
+ oy = 2 * res - oy - 1;
+ }
+ // XXX disables this branch
+ // ox = oy = -1;
+ }
+ else {
+ printf("ignoring non-4-valence multires corner %d %d %d %d : %d %d %d\t",
+ ox,
+ oy,
+ offs[oi][0],
+ offs[oi][1],
+ x,
+ y,
+ res);
+ l2 = NULL;
+ }
+
+ if (l2) {
+ // ox = res - ox - 1;
+ // oy = res - oy - 1;
+ md2 = BM_ELEM_CD_GET_VOID_P(l2, cd_loop_mdisp_offset);
+ }
+ }
+
+ if (!md2->disps || oy < 0 || oy >= res || ox < 0 || ox >= res) {
+ continue;
+ }
+
+ int idx2 = oy * res + ox;
+ float *oco2 = md == md2 ? orig[idx2] : md2->disps[idx2];
+ float co2[3];
+
+ copy_v3_v3(co2, oco2);
+
+ float dx = (float)offs[oi][0];
+ float dy = (float)offs[oi][1];
+
+ float w = 2.0f - dx * dx + dy * dy;
+
+ if (no_boundary && (ox == 0 || oy == 0 || ox == res - 1 || oy == res - 1)) {
+ // w = 2.0;
+ }
+ else if (ox == x && oy == y) {
+ // blend less away from edges
+ float au = fabs(u - 0.5) * 2.0, av = fabs(v - 0.5) * 2.0;
+ float w2 = au * au + av * av;
+
+ w = 4.0 * w2;
+ }
+ w = 1.0;
+
+ mul_v3_fl(co2, w);
+
+ tot += w;
+ add_v3_v3(co, co2);
+ }
+
+ /*
+ float vec[3];
+ copy_v3_v3(vec, f->no);
+ mul_v3_fl(vec, 0.4);
+
+ add_v3_v3(md->disps[idx1], vec);
+ sub_v3_v3(md->disps[idx1], cent);
+ mul_v3_fl(md->disps[idx1], 1.2);
+ add_v3_v3(md->disps[idx1], cent);
+
+ continue;
+ //*/
+
+ if (tot > 0.0f) {
+ mul_v3_fl(co, 1.0f / tot);
+ copy_v3_v3(md->disps[idx1], co);
+ }
+ }
}
+
+ l = l->next;
+ } while (l != f->l_first);
+
+ BLI_array_free(orig);
+}
+
+struct Object *multires_dump_grids_bmesh(struct Object *bmob, BMesh *bm);
+
+void bmo_test_mres_smooth_exec(BMesh *bm, BMOperator *op)
+{
+ BMIter iter;
+ BMFace *f;
+
+ if (!CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
+ return;
+ }
+
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ bool ok = !!BM_elem_flag_test(f, BM_ELEM_SELECT);
+ ok = ok && !BM_elem_flag_test(f, BM_ELEM_HIDDEN);
+
+ if (!ok) {
+ continue;
+ }
+
+ // bm_multires_smooth(bm, f, true);
+ // BM_multires_smooth(bm, f, false);
+ // BM_multires_smooth(bm, f, false);
+ // for (int i=0; i<5; i++) {
+ BM_face_multires_bounds_smooth(bm, f);
+ // }
+ }
+
+ multires_dump_grids_bmesh(NULL, bm);
+}
+
+void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f)
+{
+ return;
+ if (bm->multiresSpace == MULTIRES_SPACE_ABSOLUTE) {
+ BM_face_multires_stitch(bm, f);
+
+ // for (int i=0; i<5; i++) {
+ // bm_multires_smooth(bm, f, true);
+ //}
+ }
+}
+
+/**
+ * smooths boundaries between multires grids,
+ * including some borders in adjacent faces
+ */
+void BM_face_multires_stitch(BMesh *bm, BMFace *f)
+{
+ BMLoop *l;
+ BMIter liter;
+ float co[3];
+ const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
+ int sides = 0;
+
+ if (cd_loop_mdisp_offset == -1) {
+ return;
}
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
MDisps *mdl1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_mdisp_offset);
MDisps *mdl2;
- float co1[3], co2[3], co[3];
- int sides;
- int y;
+ float co1[3], co2[3];
+ int x, y;
/**
* mdisps is a grid of displacements, ordered thus:
@@ -697,7 +1021,7 @@ void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f)
mdl2 = BM_ELEM_CD_GET_VOID_P(l->radial_next->next, cd_loop_mdisp_offset);
}
- sides = (int)sqrt(mdl1->totdisp);
+ sides = (int)floor(sqrt(mdl1->totdisp) + FLT_EPSILON);
for (y = 0; y < sides; y++) {
int a1, a2, o1, o2;
@@ -709,25 +1033,129 @@ void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f)
o2 = (sides - 1) * sides + y;
}
else {
- a1 = sides * y + sides - 2;
- a2 = sides * y + sides - 2;
o1 = sides * y + sides - 1;
o2 = sides * y + sides - 1;
}
- /* magic blending numbers, hardcoded! */
- add_v3_v3v3(co1, mdl1->disps[a1], mdl2->disps[a2]);
- mul_v3_fl(co1, 0.18);
+ mid_v3_v3v3(co, mdl1->disps[o1], mdl2->disps[o2]);
+
+ copy_v3_v3(mdl1->disps[o1], co);
+ copy_v3_v3(mdl2->disps[o2], co);
+ }
+
+ BMLoop *l2 = l->prev->radial_next;
+ bool reverse = false;
- add_v3_v3v3(co2, mdl1->disps[o1], mdl2->disps[o2]);
- mul_v3_fl(co2, 0.32);
+ if (l2->v != l->v) {
+ reverse = true;
+ l2 = l2->next;
+ }
+
+ mdl2 = BM_ELEM_CD_GET_VOID_P(l2, cd_loop_mdisp_offset);
+ y = sides - 1;
+
+ if (!mdl2->disps) {
+ continue;
+ }
+
+ for (x = 0; x < sides; x++) {
+ int x2, y2, o1, o2;
+
+ if (!reverse) {
+ x2 = sides - 1;
+ y2 = x;
+ }
+ else {
+ x2 = x;
+ y2 = y;
+ }
- add_v3_v3v3(co, co1, co2);
+ o1 = y * sides + x;
+ o2 = y2 * sides + x2;
+ mid_v3_v3v3(co, mdl1->disps[o1], mdl2->disps[o2]);
copy_v3_v3(mdl1->disps[o1], co);
copy_v3_v3(mdl2->disps[o2], co);
}
}
+
+ // do exterior corners
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ MDisps *md1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_mdisp_offset);
+ BMIter l2iter;
+ BMLoop *l2;
+ int x = sides - 1, y = sides - 1;
+ int idx = y * sides + x;
+ int tot = 1;
+
+ zero_v3(co);
+
+ if (!md1->disps) {
+ continue;
+ }
+
+ add_v3_v3(co, md1->disps[idx]);
+
+ BM_ITER_ELEM (l2, &l2iter, l->v, BM_LOOPS_OF_VERT) {
+ if (l2->v != l->v) { // winding is flipped
+ l2 = l2->next;
+ }
+
+ MDisps *md2 = BM_ELEM_CD_GET_VOID_P(l2, cd_loop_mdisp_offset);
+
+ if (l == l2 || !md2->disps) {
+ continue;
+ }
+
+ add_v3_v3(co, md2->disps[idx]);
+ tot++;
+ }
+
+ mul_v3_fl(co, 1.0f / (float)tot);
+
+ BM_ITER_ELEM (l2, &l2iter, l->v, BM_LOOPS_OF_VERT) {
+ if (l2->v != l->v) { // winding is flipped
+ l2 = l2->next;
+ }
+
+ MDisps *md2 = BM_ELEM_CD_GET_VOID_P(l2, cd_loop_mdisp_offset);
+
+ if (l == l2 || !md2->disps) {
+ continue;
+ }
+
+ copy_v3_v3(md2->disps[idx], co);
+ }
+ }
+
+ // do interior corners
+ int tot = 0;
+ zero_v3(co);
+
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ MDisps *md1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_mdisp_offset);
+
+ if (!md1->disps) {
+ continue;
+ }
+
+ add_v3_v3(co, md1->disps[0]);
+ tot++;
+ }
+
+ if (tot) {
+ mul_v3_fl(co, 1.0f / (float)tot);
+ }
+
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ MDisps *md1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_mdisp_offset);
+
+ if (!md1->disps) {
+ continue;
+ }
+
+ copy_v3_v3(md1->disps[0], co);
+ }
}
/**
diff --git a/source/blender/bmesh/intern/bmesh_interp.h b/source/blender/bmesh/intern/bmesh_interp.h
index c77281bd798..686053fa78b 100644
--- a/source/blender/bmesh/intern/bmesh_interp.h
+++ b/source/blender/bmesh/intern/bmesh_interp.h
@@ -1,3 +1,4 @@
+
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -23,6 +24,7 @@
struct LinkNode;
struct MemArena;
+void BM_face_multires_stitch(BMesh *bm, BMFace *f);
void BM_loop_interp_multires_ex(BMesh *bm,
BMLoop *l_dst,
const BMFace *f_src,
diff --git a/source/blender/bmesh/intern/bmesh_log.c b/source/blender/bmesh/intern/bmesh_log.c
index 40eed6238ca..b20a1407751 100644
--- a/source/blender/bmesh/intern/bmesh_log.c
+++ b/source/blender/bmesh/intern/bmesh_log.c
@@ -1,3 +1,4 @@
+
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -35,6 +36,7 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_mempool.h"
+#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "BKE_customdata.h"
@@ -45,6 +47,8 @@
#include "BLI_strict_flags.h"
+#define CUSTOMDATA
+
struct BMLogEntry {
struct BMLogEntry *next, *prev;
@@ -75,6 +79,9 @@ struct BMLogEntry {
* This field is not guaranteed to be valid, any use of it should
* check for NULL. */
BMLog *log;
+
+ CustomData vdata, edata, ldata, pdata;
+ struct BMLogEntry *combined_prev, *combined_next;
};
struct BMLog {
@@ -93,6 +100,10 @@ struct BMLog {
GHash *id_to_elem;
GHash *elem_to_id;
+ ThreadRWMutex lock;
+
+ BMesh *bm;
+
/* All BMLogEntrys, ordered from earliest to most recent */
ListBase entries;
@@ -105,6 +116,10 @@ struct BMLog {
* entries have been applied (i.e. there is nothing left to redo.)
*/
BMLogEntry *current_entry;
+
+ int cd_origco_offset;
+ int cd_origno_offset;
+ int cd_origvcol_offset;
};
typedef struct {
@@ -112,10 +127,13 @@ typedef struct {
short no[3];
char hflag;
float mask;
+ void *customdata;
} BMLogVert;
typedef struct {
uint v_ids[3];
+ void *customdata[3];
+ void *customdata_f;
char hflag;
} BMLogFace;
@@ -125,11 +143,75 @@ typedef struct {
#define logkey_hash BLI_ghashutil_inthash_p_simple
#define logkey_cmp BLI_ghashutil_intcmp
+static void *log_ghash_lookup(BMLog *entry, GHash *gh, const void *key)
+{
+ BLI_rw_mutex_lock(&entry->lock, THREAD_LOCK_READ);
+ void *ret = BLI_ghash_lookup(gh, key);
+ BLI_rw_mutex_unlock(&entry->lock);
+
+ return ret;
+}
+
+// this is not 100% threadsafe
+static void **log_ghash_lookup_p(BMLog *entry, GHash *gh, const void *key)
+{
+ BLI_rw_mutex_lock(&entry->lock, THREAD_LOCK_READ);
+ void **ret = BLI_ghash_lookup_p(gh, key);
+ BLI_rw_mutex_unlock(&entry->lock);
+
+ return ret;
+}
+
+static void log_ghash_insert(BMLog *entry, GHash *gh, void *key, void *val)
+{
+ BLI_rw_mutex_lock(&entry->lock, THREAD_LOCK_WRITE);
+ BLI_ghash_insert(gh, key, val);
+ BLI_rw_mutex_unlock(&entry->lock);
+}
+
+static bool log_ghash_remove(
+ BMLog *entry, GHash *gh, const void *key, GHashKeyFreeFP keyfree, GHashValFreeFP valfree)
+{
+ BLI_rw_mutex_lock(&entry->lock, THREAD_LOCK_WRITE);
+ bool ret = BLI_ghash_remove(gh, key, keyfree, valfree);
+ BLI_rw_mutex_unlock(&entry->lock);
+
+ return ret;
+}
+
+static bool log_ghash_reinsert(
+ BMLog *entry, GHash *gh, void *key, void *val, GHashKeyFreeFP keyfree, GHashValFreeFP valfree)
+{
+ BLI_rw_mutex_lock(&entry->lock, THREAD_LOCK_WRITE);
+ bool ret = BLI_ghash_reinsert(gh, key, val, keyfree, valfree);
+ BLI_rw_mutex_unlock(&entry->lock);
+
+ return ret;
+}
+
+static bool log_ghash_haskey(BMLog *entry, GHash *gh, const void *key)
+{
+ BLI_rw_mutex_lock(&entry->lock, THREAD_LOCK_READ);
+ bool ret = BLI_ghash_haskey(gh, key);
+ BLI_rw_mutex_unlock(&entry->lock);
+
+ return ret;
+}
+
+static bool log_ghash_ensure_p(BMLog *entry, GHash *gh, void *key, void ***val)
+{
+ BLI_rw_mutex_lock(&entry->lock, THREAD_LOCK_WRITE);
+ bool ret = BLI_ghash_ensure_p(gh, key, val);
+ BLI_rw_mutex_unlock(&entry->lock);
+
+ return ret;
+}
+
/* Get the vertex's unique ID from the log */
static uint bm_log_vert_id_get(BMLog *log, BMVert *v)
{
- BLI_assert(BLI_ghash_haskey(log->elem_to_id, v));
- return POINTER_AS_UINT(BLI_ghash_lookup(log->elem_to_id, v));
+ BLI_assert(log_ghash_haskey(log, log->elem_to_id, v));
+ return POINTER_AS_UINT(log_ghash_lookup(log, log->elem_to_id, v));
}
/* Set the vertex's unique ID in the log */
@@ -137,23 +219,23 @@ static void bm_log_vert_id_set(BMLog *log, BMVert *v, uint id)
{
void *vid = POINTER_FROM_UINT(id);
- BLI_ghash_reinsert(log->id_to_elem, vid, v, NULL, NULL);
- BLI_ghash_reinsert(log->elem_to_id, v, vid, NULL, NULL);
+ log_ghash_reinsert(log, log->id_to_elem, vid, v, NULL, NULL);
+ log_ghash_reinsert(log, log->elem_to_id, v, vid, NULL, NULL);
}
/* Get a vertex from its unique ID */
static BMVert *bm_log_vert_from_id(BMLog *log, uint id)
{
void *key = POINTER_FROM_UINT(id);
- BLI_assert(BLI_ghash_haskey(log->id_to_elem, key));
- return BLI_ghash_lookup(log->id_to_elem, key);
+ BLI_assert(log_ghash_haskey(log, log->id_to_elem, key));
+ return log_ghash_lookup(log, log->id_to_elem, key);
}
/* Get the face's unique ID from the log */
static uint bm_log_face_id_get(BMLog *log, BMFace *f)
{
- BLI_assert(BLI_ghash_haskey(log->elem_to_id, f));
- return POINTER_AS_UINT(BLI_ghash_lookup(log->elem_to_id, f));
+ BLI_assert(log_ghash_haskey(log, log->elem_to_id, f));
+ return POINTER_AS_UINT(log_ghash_lookup(log, log->elem_to_id, f));
}
/* Set the face's unique ID in the log */
@@ -161,20 +243,74 @@ static void bm_log_face_id_set(BMLog *log, BMFace *f, uint id)
{
void *fid = POINTER_FROM_UINT(id);
- BLI_ghash_reinsert(log->id_to_elem, fid, f, NULL, NULL);
- BLI_ghash_reinsert(log->elem_to_id, f, fid, NULL, NULL);
+ log_ghash_reinsert(log, log->id_to_elem, fid, f, NULL, NULL);
+ log_ghash_reinsert(log, log->elem_to_id, f, fid, NULL, NULL);
}
/* Get a face from its unique ID */
static BMFace *bm_log_face_from_id(BMLog *log, uint id)
{
void *key = POINTER_FROM_UINT(id);
- BLI_assert(BLI_ghash_haskey(log->id_to_elem, key));
- return BLI_ghash_lookup(log->id_to_elem, key);
+ BLI_assert(log_ghash_haskey(log, log->id_to_elem, key));
+ return log_ghash_lookup(log, log->id_to_elem, key);
}
/************************ BMLogVert / BMLogFace ***********************/
+static void bm_log_vert_customdata(BMesh *bm, BMLog *log, BMVert *v, BMLogVert *lv)
+{
+#ifdef CUSTOMDATA
+ // if (!lv) {
+ // return;
+ //}
+ BMLogEntry *entry = log->current_entry;
+
+ if (!entry) {
+ return;
+ }
+
+ if (lv->customdata) {
+ BLI_mempool_free(entry->vdata.pool, lv->customdata);
+ lv->customdata = NULL;
+ }
+
+ CustomData_bmesh_copy_data(&bm->vdata, &entry->vdata, v->head.data, &lv->customdata);
+#endif
+}
+
+static void bm_log_face_customdata(BMesh *bm, BMLog *log, BMFace *f, BMLogFace *lf)
+{
+#ifdef CUSTOMDATA
+ BMLogEntry *entry = log->current_entry;
+
+ if (!entry || !lf) {
+ printf("bmlog error\n");
+ return;
+ }
+
+ if (lf->customdata_f) {
+ BLI_mempool_free(entry->pdata.pool, lf->customdata_f);
+ lf->customdata_f = NULL;
+ }
+
+ CustomData_bmesh_copy_data(&bm->pdata, &entry->pdata, f->head.data, &lf->customdata_f);
+
+ BMLoop *l1 = f->l_first;
+ BMLoop *l2 = f->l_first->next;
+ BMLoop *l3 = f->l_first->prev;
+ BMLoop *ls[3] = {l1, l2, l3};
+
+ for (int i = 0; i < 3; i++) {
+ if (lf->customdata[i]) {
+ BLI_mempool_free(entry->ldata.pool, lf->customdata[i]);
+ lf->customdata[i] = NULL;
+ }
+
+ CustomData_bmesh_copy_data(&bm->ldata, &entry->ldata, ls[i]->head.data, &lf->customdata[i]);
+ }
+#endif
+}
+
/* Get a vertex's paint-mask value
*
* Returns zero if no paint-mask layer is present */
@@ -197,12 +333,17 @@ static void vert_mask_set(BMVert *v, const float new_mask, const int cd_vert_mas
}
/* Update a BMLogVert with data from a BMVert */
-static void bm_log_vert_bmvert_copy(BMLogVert *lv, BMVert *v, const int cd_vert_mask_offset)
+static void bm_log_vert_bmvert_copy(BMLog *log,
+ BMLogVert *lv,
+ BMVert *v,
+ const int cd_vert_mask_offset)
{
copy_v3_v3(lv->co, v->co);
normal_float_to_short_v3(lv->no, v->no);
lv->mask = vert_mask_get(v, cd_vert_mask_offset);
lv->hflag = v->head.hflag;
+
+ bm_log_vert_customdata(log->bm, log, v, lv);
}
/* Allocate and initialize a BMLogVert */
@@ -210,8 +351,9 @@ static BMLogVert *bm_log_vert_alloc(BMLog *log, BMVert *v, const int cd_vert_mas
{
BMLogEntry *entry = log->current_entry;
BMLogVert *lv = BLI_mempool_alloc(entry->pool_verts);
+ lv->customdata = NULL;
- bm_log_vert_bmvert_copy(lv, v, cd_vert_mask_offset);
+ bm_log_vert_bmvert_copy(log, lv, v, cd_vert_mask_offset);
return lv;
}
@@ -223,6 +365,7 @@ static BMLogFace *bm_log_face_alloc(BMLog *log, BMFace *f)
BMLogFace *lf = BLI_mempool_alloc(entry->pool_faces);
BMVert *v[3];
+ lf->customdata_f = lf->customdata[0] = lf->customdata[1] = lf->customdata[2] = NULL;
BLI_assert(f->len == 3);
// BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v, 3);
@@ -251,7 +394,7 @@ static void bm_log_verts_unmake(BMesh *bm, BMLog *log, GHash *verts)
/* Ensure the log has the final values of the vertex before
* deleting it */
- bm_log_vert_bmvert_copy(lv, v, cd_vert_mask_offset);
+ bm_log_vert_bmvert_copy(log, lv, v, cd_vert_mask_offset);
BM_vert_kill(bm, v);
}
@@ -264,6 +407,12 @@ static void bm_log_faces_unmake(BMesh *bm, BMLog *log, GHash *faces)
void *key = BLI_ghashIterator_getKey(&gh_iter);
uint id = POINTER_AS_UINT(key);
BMFace *f = bm_log_face_from_id(log, id);
+
+ if (!f) {
+ printf("dyntopo error in %s\n", __func__);
+ continue;
+ }
+
BMEdge *e_tri[3];
BMLoop *l_iter;
int i;
@@ -283,9 +432,10 @@ static void bm_log_faces_unmake(BMesh *bm, BMLog *log, GHash *faces)
}
}
-static void bm_log_verts_restore(BMesh *bm, BMLog *log, GHash *verts)
+static void bm_log_verts_restore(BMesh *bm, BMLog *log, GHash *verts, BMLogEntry *entry)
{
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
+ int cd_vcol_offset = CustomData_get_offset(&bm->vdata, CD_PROP_COLOR);
GHashIterator gh_iter;
GHASH_ITER (gh_iter, verts) {
@@ -296,10 +446,32 @@ static void bm_log_verts_restore(BMesh *bm, BMLog *log, GHash *verts)
v->head.hflag = lv->hflag;
normal_short_to_float_v3(v->no, lv->no);
bm_log_vert_id_set(log, v, POINTER_AS_UINT(key));
+
+#ifdef CUSTOMDATA
+ if (lv->customdata) {
+ CustomData_bmesh_copy_data(&entry->vdata, &bm->vdata, lv->customdata, &v->head.data);
+ }
+#endif
+
+ if (log->cd_origco_offset >= 0) {
+ float *oco = BM_ELEM_CD_GET_VOID_P(v, log->cd_origco_offset);
+ copy_v3_v3(oco, v->co);
+ }
+
+ if (log->cd_origno_offset >= 0) {
+ float *ono = BM_ELEM_CD_GET_VOID_P(v, log->cd_origno_offset);
+ copy_v3_v3(ono, v->no);
+ }
+
+ if (log->cd_origvcol_offset >= 0) {
+ float *ocolor = BM_ELEM_CD_GET_VOID_P(v, log->cd_origvcol_offset);
+ float *color = BM_ELEM_CD_GET_VOID_P(v, cd_vcol_offset);
+ copy_v3_v3(ocolor, color);
+ }
}
}
-static void bm_log_faces_restore(BMesh *bm, BMLog *log, GHash *faces)
+static void bm_log_faces_restore(BMesh *bm, BMLog *log, GHash *faces, BMLogEntry *entry)
{
GHashIterator gh_iter;
GHASH_ITER (gh_iter, faces) {
@@ -315,13 +487,30 @@ static void bm_log_faces_restore(BMesh *bm, BMLog *log, GHash *faces)
f = BM_face_create_verts(bm, v, 3, NULL, BM_CREATE_NOP, true);
f->head.hflag = lf->hflag;
bm_log_face_id_set(log, f, POINTER_AS_UINT(key));
+
+#ifdef CUSTOMDATA
+ if (lf->customdata_f) {
+ CustomData_bmesh_copy_data(&entry->pdata, &bm->pdata, lf->customdata_f, &f->head.data);
+ }
+
+ BMLoop *ls[3] = {f->l_first, f->l_first->next, f->l_first->prev};
+
+ for (int i = 0; i < 3; i++) {
+ if (lf->customdata[i]) {
+ CustomData_bmesh_copy_data(
+ &entry->ldata, &bm->ldata, lf->customdata[i], &ls[i]->head.data);
+ }
+ }
+#endif
}
}
-static void bm_log_vert_values_swap(BMesh *bm, BMLog *log, GHash *verts)
+static void bm_log_vert_values_swap(BMesh *bm, BMLog *log, GHash *verts, BMLogEntry *entry)
{
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
+ int cd_vcol_offset = CustomData_get_offset(&bm->vdata, CD_PROP_COLOR);
+
GHashIterator gh_iter;
GHASH_ITER (gh_iter, verts) {
void *key = BLI_ghashIterator_getKey(&gh_iter);
@@ -339,10 +528,32 @@ static void bm_log_vert_values_swap(BMesh *bm, BMLog *log, GHash *verts)
mask = lv->mask;
lv->mask = vert_mask_get(v, cd_vert_mask_offset);
vert_mask_set(v, mask, cd_vert_mask_offset);
+
+#ifdef CUSTOMDATA
+ if (lv->customdata) {
+ CustomData_bmesh_copy_data(&entry->vdata, &bm->vdata, lv->customdata, &v->head.data);
+ }
+#endif
+
+ if (log->cd_origco_offset >= 0) {
+ float *oco = BM_ELEM_CD_GET_VOID_P(v, log->cd_origco_offset);
+ copy_v3_v3(oco, v->co);
+ }
+
+ if (log->cd_origno_offset >= 0) {
+ float *ono = BM_ELEM_CD_GET_VOID_P(v, log->cd_origno_offset);
+ copy_v3_v3(ono, v->no);
+ }
+
+ if (log->cd_origvcol_offset >= 0) {
+ float *ocolor = BM_ELEM_CD_GET_VOID_P(v, log->cd_origvcol_offset);
+ float *color = BM_ELEM_CD_GET_VOID_P(v, cd_vcol_offset);
+ copy_v3_v3(ocolor, color);
+ }
}
}
-static void bm_log_face_values_swap(BMLog *log, GHash *faces)
+static void bm_log_face_values_swap(BMLog *log, GHash *faces, BMLogEntry *entry)
{
GHashIterator gh_iter;
GHASH_ITER (gh_iter, faces) {
@@ -352,6 +563,22 @@ static void bm_log_face_values_swap(BMLog *log, GHash *faces)
BMFace *f = bm_log_face_from_id(log, id);
SWAP(char, f->head.hflag, lf->hflag);
+
+#ifdef CUSTOMDATA
+ if (lf->customdata_f) {
+ CustomData_bmesh_copy_data(&entry->pdata, &log->bm->pdata, lf->customdata_f, &f->head.data);
+ }
+
+ BMLoop *ls[3] = {f->l_first, f->l_first->next, f->l_first->prev};
+
+ for (int i = 0; i < 3; i++) {
+ if (lf->customdata[i]) {
+ CustomData_bmesh_copy_data(
+ &entry->ldata, &log->bm->ldata, lf->customdata[i], &ls[i]->head.data);
+ }
+ }
+#endif
+
}
}
@@ -409,6 +636,24 @@ static void bm_log_entry_free(BMLogEntry *entry)
BLI_mempool_destroy(entry->pool_verts);
BLI_mempool_destroy(entry->pool_faces);
+
+ if (entry->vdata.pool) {
+ BLI_mempool_destroy(entry->vdata.pool);
+ }
+ if (entry->edata.pool) {
+ BLI_mempool_destroy(entry->edata.pool);
+ }
+ if (entry->ldata.pool) {
+ BLI_mempool_destroy(entry->ldata.pool);
+ }
+ if (entry->pdata.pool) {
+ BLI_mempool_destroy(entry->pdata.pool);
+ }
+
+ CustomData_free(&entry->vdata, 0);
+ CustomData_free(&entry->edata, 0);
+ CustomData_free(&entry->ldata, 0);
+ CustomData_free(&entry->pdata, 0);
}
static void bm_log_id_ghash_retake(RangeTreeUInt *unused_ids, GHash *id_ghash)
@@ -468,16 +713,30 @@ static void bm_log_id_ghash_release(BMLog *log, GHash *id_ghash)
/***************************** Public API *****************************/
+void BM_log_set_cd_offsets(BMLog *log,
+ int cd_origco_offset,
+ int cd_origno_offset,
+ int cd_origvol_offset)
+{
+ log->cd_origco_offset = cd_origco_offset;
+ log->cd_origno_offset = cd_origno_offset;
+ log->cd_origvcol_offset = cd_origvol_offset;
+}
+
/* Allocate, initialize, and assign a new BMLog */
-BMLog *BM_log_create(BMesh *bm)
+BMLog *BM_log_create(BMesh *bm, int cd_origco_offset, int cd_origno_offset, int cd_origvcol_offset)
{
BMLog *log = MEM_callocN(sizeof(*log), __func__);
const uint reserve_num = (uint)(bm->totvert + bm->totface);
+ BLI_rw_mutex_init(&log->lock);
+
log->unused_ids = range_tree_uint_alloc(0, (uint)-1);
log->id_to_elem = BLI_ghash_new_ex(logkey_hash, logkey_cmp, __func__, reserve_num);
log->elem_to_id = BLI_ghash_ptr_new_ex(__func__, reserve_num);
+ BM_log_set_cd_offsets(log, cd_origco_offset, cd_origno_offset, cd_origvcol_offset);
+
/* Assign IDs to all existing vertices and faces */
bm_log_assign_ids(bm, log);
@@ -516,7 +775,7 @@ void BM_log_cleanup_entry(BMLogEntry *entry)
*/
BMLog *BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry)
{
- BMLog *log = BM_log_create(bm);
+ BMLog *log = BM_log_create(bm, -1, -1, -1);
if (entry->prev) {
log->current_entry = entry;
@@ -560,6 +819,8 @@ void BM_log_free(BMLog *log)
{
BMLogEntry *entry;
+ BLI_rw_mutex_end(&log->lock);
+
if (log->unused_ids) {
range_tree_uint_free(log->unused_ids);
}
@@ -618,7 +879,7 @@ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
BM_ITER_MESH_INDEX (v, &bm_iter, bm, BM_VERTS_OF_MESH, i) {
const uint id = bm_log_vert_id_get(log, v);
const void *key = POINTER_FROM_UINT(id);
- const void *val = BLI_ghash_lookup(id_to_idx, key);
+ const void *val = log_ghash_lookup(log, id_to_idx, key);
varr[i] = POINTER_AS_UINT(val);
}
BLI_ghash_free(id_to_idx, NULL, NULL);
@@ -628,7 +889,7 @@ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
BM_ITER_MESH_INDEX (f, &bm_iter, bm, BM_FACES_OF_MESH, i) {
const uint id = bm_log_face_id_get(log, f);
const void *key = POINTER_FROM_UINT(id);
- const void *val = BLI_ghash_lookup(id_to_idx, key);
+ const void *val = log_ghash_lookup(log, id_to_idx, key);
farr[i] = POINTER_AS_UINT(val);
}
BLI_ghash_free(id_to_idx, NULL, NULL);
@@ -639,6 +900,35 @@ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
MEM_freeN(farr);
}
+BMLogEntry *BM_log_entry_check_customdata(BMesh *bm, BMLog *log)
+{
+ BMLogEntry *entry = log->current_entry;
+
+ if (!entry) {
+ printf("no current entry; creating...\n");
+ fflush(stdout);
+ return BM_log_entry_add_ex(bm, log, false);
+ }
+
+#ifndef CUSTOMDATA
+ return entry;
+#else
+
+ CustomData *cd1[4] = {&bm->vdata, &bm->edata, &bm->ldata, &bm->pdata};
+ CustomData *cd2[4] = {&entry->vdata, &entry->edata, &entry->ldata, &entry->pdata};
+
+ for (int i = 0; i < 4; i++) {
+ if (!CustomData_layout_is_same(cd1[i], cd2[i])) {
+ printf("Customdata changed for undo\n");
+ fflush(stdout);
+ return BM_log_entry_add_ex(bm, log, true);
+ }
+ }
+
+ return entry;
+#endif
+}
+
/* Start a new log entry and update the log entry list
*
* If the log entry list is empty, or if the current log entry is the
@@ -649,8 +939,15 @@ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
*
* In either case, the new entry is set as the current log entry.
*/
-BMLogEntry *BM_log_entry_add(BMLog *log)
+BMLogEntry *BM_log_entry_add(BMesh *bm, BMLog *log)
+{
+ return BM_log_entry_add_ex(bm, log, false);
+}
+
+BMLogEntry *BM_log_entry_add_ex(BMesh *bm, BMLog *log, bool combine_with_last)
{
+ log->bm = bm;
+
/* WARNING: this is now handled by the UndoSystem: BKE_UNDOSYS_TYPE_SCULPT
* freeing here causes unnecessary complications. */
BMLogEntry *entry;
@@ -673,6 +970,25 @@ BMLogEntry *BM_log_entry_add(BMLog *log)
entry->log = log;
log->current_entry = entry;
+#ifdef CUSTOMDATA
+ if (combine_with_last) {
+ if (log->current_entry) {
+ log->current_entry->combined_next = entry;
+ }
+ entry->combined_prev = log->current_entry;
+ }
+
+ CustomData_copy_all_layout(&bm->vdata, &entry->vdata);
+ CustomData_copy_all_layout(&bm->edata, &entry->edata);
+ CustomData_copy_all_layout(&bm->ldata, &entry->ldata);
+ CustomData_copy_all_layout(&bm->pdata, &entry->pdata);
+
+ CustomData_bmesh_init_pool(&entry->vdata, 0, BM_VERT);
+ CustomData_bmesh_init_pool(&entry->edata, 0, BM_EDGE);
+ CustomData_bmesh_init_pool(&entry->ldata, 0, BM_LOOP);
+ CustomData_bmesh_init_pool(&entry->pdata, 0, BM_FACE);
+#endif
+
return entry;
}
@@ -758,6 +1074,9 @@ void BM_log_undo(BMesh *bm, BMLog *log)
{
BMLogEntry *entry = log->current_entry;
+ bm->elem_index_dirty |= BM_VERT | BM_EDGE | BM_FACE;
+ bm->elem_table_dirty |= BM_VERT | BM_EDGE | BM_FACE;
+
if (entry) {
log->current_entry = entry->prev;
@@ -766,12 +1085,12 @@ void BM_log_undo(BMesh *bm, BMLog *log)
bm_log_verts_unmake(bm, log, entry->added_verts);
/* Restore deleted verts and faces */
- bm_log_verts_restore(bm, log, entry->deleted_verts);
- bm_log_faces_restore(bm, log, entry->deleted_faces);
+ bm_log_verts_restore(bm, log, entry->deleted_verts, entry);
+ bm_log_faces_restore(bm, log, entry->deleted_faces, entry);
/* Restore vertex coordinates, mask, and hflag */
- bm_log_vert_values_swap(bm, log, entry->modified_verts);
- bm_log_face_values_swap(log, entry->modified_faces);
+ bm_log_vert_values_swap(bm, log, entry->modified_verts, entry);
+ bm_log_face_values_swap(log, entry->modified_faces, entry);
}
}
@@ -782,6 +1101,9 @@ void BM_log_redo(BMesh *bm, BMLog *log)
{
BMLogEntry *entry = log->current_entry;
+ bm->elem_index_dirty |= BM_VERT | BM_EDGE | BM_FACE;
+ bm->elem_table_dirty |= BM_VERT | BM_EDGE | BM_FACE;
+
if (!entry) {
/* Currently at the beginning of the undo stack, move to first entry */
entry = log->entries.first;
@@ -803,12 +1125,12 @@ void BM_log_redo(BMesh *bm, BMLog *log)
bm_log_verts_unmake(bm, log, entry->deleted_verts);
/* Restore previously added verts and faces */
- bm_log_verts_restore(bm, log, entry->added_verts);
- bm_log_faces_restore(bm, log, entry->added_faces);
+ bm_log_verts_restore(bm, log, entry->added_verts, entry);
+ bm_log_faces_restore(bm, log, entry->added_faces, entry);
/* Restore vertex coordinates, mask, and hflag */
- bm_log_vert_values_swap(bm, log, entry->modified_verts);
- bm_log_face_values_swap(log, entry->modified_faces);
+ bm_log_vert_values_swap(bm, log, entry->modified_verts, entry);
+ bm_log_face_values_swap(log, entry->modified_faces, entry);
}
}
@@ -835,7 +1157,10 @@ void BM_log_redo(BMesh *bm, BMLog *log)
* state so that a subsequent redo operation will restore the newer
* vertex state.
*/
-void BM_log_vert_before_modified(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
+void BM_log_vert_before_modified(BMLog *log,
+ BMVert *v,
+ const int cd_vert_mask_offset,
+ bool log_customdata)
{
BMLogEntry *entry = log->current_entry;
BMLogVert *lv;
@@ -844,13 +1169,17 @@ void BM_log_vert_before_modified(BMLog *log, BMVert *v, const int cd_vert_mask_o
void **val_p;
/* Find or create the BMLogVert entry */
- if ((lv = BLI_ghash_lookup(entry->added_verts, key))) {
- bm_log_vert_bmvert_copy(lv, v, cd_vert_mask_offset);
+ if ((lv = log_ghash_lookup(log, entry->added_verts, key))) {
+ bm_log_vert_bmvert_copy(log, lv, v, cd_vert_mask_offset);
}
- else if (!BLI_ghash_ensure_p(entry->modified_verts, key, &val_p)) {
+ else if (!log_ghash_ensure_p(log, entry->modified_verts, key, &val_p)) {
lv = bm_log_vert_alloc(log, v, cd_vert_mask_offset);
*val_p = lv;
}
+
+ if (lv && log_customdata) {
+ bm_log_vert_customdata(log->bm, log, v, lv);
+ }
}
/* Log a new vertex as added to the BMesh
@@ -867,7 +1196,9 @@ void BM_log_vert_added(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
bm_log_vert_id_set(log, v, v_id);
lv = bm_log_vert_alloc(log, v, cd_vert_mask_offset);
- BLI_ghash_insert(log->current_entry->added_verts, key, lv);
+ log_ghash_insert(log, log->current_entry->added_verts, key, lv);
+
+ // bm_log_vert_customdata(log->bm, log, v, lv);
}
/* Log a face before it is modified
@@ -882,7 +1213,9 @@ void BM_log_face_modified(BMLog *log, BMFace *f)
void *key = POINTER_FROM_UINT(f_id);
lf = bm_log_face_alloc(log, f);
- BLI_ghash_insert(log->current_entry->modified_faces, key, lf);
+ log_ghash_insert(log, log->current_entry->modified_faces, key, lf);
+
+ bm_log_face_customdata(log->bm, log, f, lf);
}
/* Log a new face as added to the BMesh
@@ -902,7 +1235,9 @@ void BM_log_face_added(BMLog *log, BMFace *f)
bm_log_face_id_set(log, f, f_id);
lf = bm_log_face_alloc(log, f);
- BLI_ghash_insert(log->current_entry->added_faces, key, lf);
+ log_ghash_insert(log, log->current_entry->added_faces, key, lf);
+
+ bm_log_face_customdata(log->bm, log, f, lf);
}
/* Log a vertex as removed from the BMesh
@@ -928,23 +1263,27 @@ void BM_log_vert_removed(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
void *key = POINTER_FROM_UINT(v_id);
/* if it has a key, it shouldn't be NULL */
- BLI_assert(!!BLI_ghash_lookup(entry->added_verts, key) ==
- !!BLI_ghash_haskey(entry->added_verts, key));
+ BLI_assert(!!log_ghash_lookup(log, entry->added_verts, key) ==
+ !!log_ghash_haskey(log, entry->added_verts, key));
- if (BLI_ghash_remove(entry->added_verts, key, NULL, NULL)) {
+ if (log_ghash_remove(log, entry->added_verts, key, NULL, NULL)) {
range_tree_uint_release(log->unused_ids, v_id);
}
else {
BMLogVert *lv, *lv_mod;
lv = bm_log_vert_alloc(log, v, cd_vert_mask_offset);
- BLI_ghash_insert(entry->deleted_verts, key, lv);
+ log_ghash_insert(log, entry->deleted_verts, key, lv);
/* If the vertex was modified before deletion, ensure that the
* original vertex values are stored */
- if ((lv_mod = BLI_ghash_lookup(entry->modified_verts, key))) {
+ if ((lv_mod = log_ghash_lookup(log, entry->modified_verts, key))) {
(*lv) = (*lv_mod);
- BLI_ghash_remove(entry->modified_verts, key, NULL, NULL);
+ log_ghash_remove(log, entry->modified_verts, key, NULL, NULL);
+ }
+
+ if (lv) {
+ bm_log_vert_customdata(log->bm, log, v, lv);
}
}
}
@@ -969,17 +1308,21 @@ void BM_log_face_removed(BMLog *log, BMFace *f)
void *key = POINTER_FROM_UINT(f_id);
/* if it has a key, it shouldn't be NULL */
- BLI_assert(!!BLI_ghash_lookup(entry->added_faces, key) ==
- !!BLI_ghash_haskey(entry->added_faces, key));
+ BLI_assert(!!log_ghash_lookup(log, entry->added_faces, key) ==
+ !!log_ghash_haskey(log, entry->added_faces, key));
- if (BLI_ghash_remove(entry->added_faces, key, NULL, NULL)) {
+ if (log_ghash_remove(log, entry->added_faces, key, NULL, NULL)) {
range_tree_uint_release(log->unused_ids, f_id);
}
else {
BMLogFace *lf;
lf = bm_log_face_alloc(log, f);
- BLI_ghash_insert(entry->deleted_faces, key, lf);
+ log_ghash_insert(log, entry->deleted_faces, key, lf);
+
+ if (lf) {
+ bm_log_face_customdata(log->bm, log, f, lf);
+ }
}
}
@@ -1042,9 +1385,9 @@ const float *BM_log_original_vert_co(BMLog *log, BMVert *v)
BLI_assert(entry);
- BLI_assert(BLI_ghash_haskey(entry->modified_verts, key));
+ BLI_assert(log_ghash_haskey(log, entry->modified_verts, key));
- lv = BLI_ghash_lookup(entry->modified_verts, key);
+ lv = log_ghash_lookup(log, entry->modified_verts, key);
return lv->co;
}
@@ -1060,9 +1403,9 @@ const short *BM_log_original_vert_no(BMLog *log, BMVert *v)
BLI_assert(entry);
- BLI_assert(BLI_ghash_haskey(entry->modified_verts, key));
+ BLI_assert(log_ghash_haskey(log, entry->modified_verts, key));
- lv = BLI_ghash_lookup(entry->modified_verts, key);
+ lv = log_ghash_lookup(log, entry->modified_verts, key);
return lv->no;
}
@@ -1078,9 +1421,9 @@ float BM_log_original_mask(BMLog *log, BMVert *v)
BLI_assert(entry);
- BLI_assert(BLI_ghash_haskey(entry->modified_verts, key));
+ BLI_assert(log_ghash_haskey(log, entry->modified_verts, key));
- lv = BLI_ghash_lookup(entry->modified_verts, key);
+ lv = log_ghash_lookup(log, entry->modified_verts, key);
return lv->mask;
}
@@ -1093,9 +1436,9 @@ void BM_log_original_vert_data(BMLog *log, BMVert *v, const float **r_co, const
BLI_assert(entry);
- BLI_assert(BLI_ghash_haskey(entry->modified_verts, key));
+ BLI_assert(log_ghash_haskey(log, entry->modified_verts, key));
- lv = BLI_ghash_lookup(entry->modified_verts, key);
+ lv = log_ghash_lookup(log, entry->modified_verts, key);
*r_co = lv->co;
*r_no = lv->no;
}
diff --git a/source/blender/bmesh/intern/bmesh_log.h b/source/blender/bmesh/intern/bmesh_log.h
index 5c0ca78bddf..470515db157 100644
--- a/source/blender/bmesh/intern/bmesh_log.h
+++ b/source/blender/bmesh/intern/bmesh_log.h
@@ -29,7 +29,11 @@ typedef struct BMLog BMLog;
typedef struct BMLogEntry BMLogEntry;
/* Allocate and initialize a new BMLog */
-BMLog *BM_log_create(BMesh *bm);
+BMLog *BM_log_create(BMesh *bm, int cd_origco_offset, int cd_origno_offset, int cd_origvol_offset);
+void BM_log_set_cd_offsets(BMLog *log,
+ int cd_origco_offset,
+ int cd_origno_offset,
+ int cd_origvcol_offset);
/* Allocate and initialize a new BMLog using existing BMLogEntries */
BMLog *BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry);
@@ -44,7 +48,10 @@ int BM_log_length(const BMLog *log);
void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log);
/* Start a new log entry and update the log entry list */
-BMLogEntry *BM_log_entry_add(BMLog *log);
+BMLogEntry *BM_log_entry_add(BMesh *bm, BMLog *log);
+BMLogEntry *BM_log_entry_add_ex(BMesh *bm, BMLog *log, bool combine_with_last);
+
+BMLogEntry *BM_log_entry_check_customdata(BMesh *bm, BMLog *log);
/* Mark all used ids as unused for this node */
void BM_log_cleanup_entry(BMLogEntry *entry);
@@ -59,7 +66,10 @@ void BM_log_undo(BMesh *bm, BMLog *log);
void BM_log_redo(BMesh *bm, BMLog *log);
/* Log a vertex before it is modified */
-void BM_log_vert_before_modified(BMLog *log, struct BMVert *v, const int cd_vert_mask_offset);
+void BM_log_vert_before_modified(BMLog *log,
+ struct BMVert *v,
+ const int cd_vert_mask_offset,
+ bool log_customdata);
/* Log a new vertex as added to the BMesh */
void BM_log_vert_added(BMLog *log, struct BMVert *v, const int cd_vert_mask_offset);
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c
index d479a555a58..5c43720f635 100644
--- a/source/blender/bmesh/intern/bmesh_marking.c
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -73,13 +73,19 @@ static void recount_totsels(BMesh *bm)
static bool bm_vert_is_edge_select_any_other(const BMVert *v, const BMEdge *e_first)
{
const BMEdge *e_iter = e_first;
+ int i = 0;
/* start by stepping over the current edge */
- while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first) {
+ while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first && i++ < 1000) {
if (BM_elem_flag_test(e_iter, BM_ELEM_SELECT)) {
return true;
}
}
+
+ if (i >= 1000) {
+ fprintf(stderr, "bmesh mesh error in %s\n", __func__);
+ }
+
return false;
}
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index 5e879d41d43..2f17066da25 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -1965,6 +1965,11 @@ void BM_custom_loop_normals_from_vector_layer(BMesh *bm, bool add_sharp_edges)
bm->spacearr_dirty &= ~(BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL);
}
+static void bmesh_convert_space(BMesh *bm, MultiResSpace from, MultiResSpace to)
+{
+
+}
+
/**
* \brief BMesh Begin Edit
*
@@ -1972,24 +1977,22 @@ void BM_custom_loop_normals_from_vector_layer(BMesh *bm, bool add_sharp_edges)
* the editing operations are done. These are called by the tools/operator
* API for each time a tool is executed.
*/
-void bmesh_edit_begin(BMesh *UNUSED(bm), BMOpTypeFlag UNUSED(type_flag))
+void bmesh_edit_begin(BMesh *bm, BMOpTypeFlag type_flag)
{
/* Most operators seem to be using BMO_OPTYPE_FLAG_UNTAN_MULTIRES to change the MDisps to
* absolute space during mesh edits. With this enabled, changes to the topology
* (loop cuts, edge subdivides, etc) are not reflected in the higher levels of
* the mesh at all, which doesn't seem right. Turning off completely for now,
* until this is shown to be better for certain types of mesh edits. */
-#ifdef BMOP_UNTAN_MULTIRES_ENABLED
/* switch multires data out of tangent space */
if ((type_flag & BMO_OPTYPE_FLAG_UNTAN_MULTIRES) &&
CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
- bmesh_mdisps_space_set(bm, MULTIRES_SPACE_TANGENT, MULTIRES_SPACE_ABSOLUTE);
-
+ //bmesh_mdisps_space_set(bm, MULTIRES_SPACE_TANGENT, MULTIRES_SPACE_ABSOLUTE);
+ BM_enter_multires_space(NULL, bm, MULTIRES_SPACE_ABSOLUTE);
/* ensure correct normals, if possible */
- bmesh_rationalize_normals(bm, 0);
- BM_mesh_normals_update(bm);
+ //bmesh_rationalize_normals(bm, 0);
+ //BM_mesh_normals_update(bm);
}
-#endif
}
/**
@@ -2000,17 +2003,10 @@ void bmesh_edit_end(BMesh *bm, BMOpTypeFlag type_flag)
ListBase select_history;
/* BMO_OPTYPE_FLAG_UNTAN_MULTIRES disabled for now, see comment above in bmesh_edit_begin. */
-#ifdef BMOP_UNTAN_MULTIRES_ENABLED
/* switch multires data into tangent space */
- if ((flag & BMO_OPTYPE_FLAG_UNTAN_MULTIRES) && CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
- /* set normals to their previous winding */
- bmesh_rationalize_normals(bm, 1);
- bmesh_mdisps_space_set(bm, MULTIRES_SPACE_ABSOLUTE, MULTIRES_SPACE_TANGENT);
+ if ((type_flag & BMO_OPTYPE_FLAG_UNTAN_MULTIRES) && CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
+ BM_enter_multires_space(NULL, bm, MULTIRES_SPACE_TANGENT);
}
- else if (flag & BMO_OP_FLAG_RATIONALIZE_NORMALS) {
- bmesh_rationalize_normals(bm, 1);
- }
-#endif
/* compute normals, clear temp flags and flush selections */
if (type_flag & BMO_OPTYPE_FLAG_NORMALS_CALC) {
diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h
index c1c2f17d7c1..313b2bca59d 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.h
+++ b/source/blender/bmesh/intern/bmesh_mesh.h
@@ -22,6 +22,11 @@
#include "bmesh_class.h"
+typedef enum {
+ MULTIRES_SPACE_TANGENT, //convert absolute to tangent
+ MULTIRES_SPACE_ABSOLUTE //convert tangent to absolute
+} MultiResSpace;
+
struct BMAllocTemplate;
struct BMLoopNorEditDataArray;
struct MLoopNorSpaceArray;
diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.c b/source/blender/bmesh/intern/bmesh_mesh_convert.c
index ba413c3c547..7ab7e9aaa6d 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_convert.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.c
@@ -176,8 +176,27 @@ static BMFace *bm_face_create_from_mpoly(
return BM_face_create(bm, verts, edges, mp->totloop, NULL, BM_CREATE_SKIP_CD);
}
+void BM_enter_multires_space(Object *ob, BMesh *bm, int space) {
+ if (!bm->haveMultiResSettings && ob) {
+ MultiresModifierData *mmd = get_multires_modifier(NULL, ob, true);
+ if (mmd) {
+ bm->multires = *mmd;
+ bm->haveMultiResSettings = true;
+ bm->multiresSpace = MULTIRES_SPACE_TANGENT;
+ }
+ }
+
+ if (!bm->haveMultiResSettings || !CustomData_has_layer(&bm->ldata, CD_MDISPS) || space == bm->multiresSpace) {
+ return;
+ }
+
+ BKE_multires_bmesh_space_set(ob, bm, space);
+ bm->multiresSpace = space;
+}
+
/**
* \brief Mesh -> BMesh
+ * \param ob: object that owns bm, may be NULL (which will disable multires space change)
* \param bm: The mesh to write into, while this is typically a newly created BMesh,
* merging into existing data is supported.
* Note the custom-data layout isn't used.
@@ -186,7 +205,7 @@ static BMFace *bm_face_create_from_mpoly(
*
* \warning This function doesn't calculate face normals.
*/
-void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshParams *params)
+void BM_mesh_bm_from_me(Object *ob, BMesh *bm, const Mesh *me, const struct BMeshFromMeshParams *params)
{
const bool is_new = !(bm->totvert || (bm->vdata.totlayer || bm->edata.totlayer ||
bm->pdata.totlayer || bm->ldata.totlayer));
@@ -203,6 +222,15 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
CustomData_MeshMasks mask = CD_MASK_BMESH;
CustomData_MeshMasks_update(&mask, &params->cd_mask_extra);
+ MultiresModifierData *mmd = ob ? get_multires_modifier(NULL, ob, true) : NULL;
+ if (mmd) {
+ bm->multires = *mmd;
+ bm->haveMultiResSettings = true;
+ bm->multiresSpace = MULTIRES_SPACE_TANGENT;
+ } else {
+ bm->haveMultiResSettings = false;
+ }
+
if (!me || !me->totvert) {
if (me && is_new) { /* No verts? still copy custom-data layout. */
CustomData_copy(&me->vdata, &bm->vdata, mask.vmask, CD_ASSIGN, 0);
@@ -586,7 +614,7 @@ BLI_INLINE void bmesh_quick_edgedraw_flag(MEdge *med, BMEdge *e)
*
* \param bmain: May be NULL in case \a calc_object_remap parameter option is not set.
*/
-void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params)
+void BM_mesh_bm_to_me(Main *bmain, Object *ob, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params)
{
MEdge *med;
BMVert *v, *eve;
@@ -595,6 +623,11 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
BMIter iter;
int i, j;
+ //ensure multires space is correct
+ if (bm->haveMultiResSettings && bm->multiresSpace != MULTIRES_SPACE_TANGENT) {
+ BM_enter_multires_space(ob, bm, MULTIRES_SPACE_TANGENT);
+ }
+
const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.h b/source/blender/bmesh/intern/bmesh_mesh_convert.h
index 1b5d001d35d..b2c9037318c 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_convert.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.h
@@ -43,7 +43,9 @@ struct BMeshFromMeshParams {
int active_shapekey;
struct CustomData_MeshMasks cd_mask_extra;
};
-void BM_mesh_bm_from_me(BMesh *bm, const struct Mesh *me, const struct BMeshFromMeshParams *params)
+
+struct Object;
+void BM_mesh_bm_from_me(struct Object *ob, BMesh *bm, const struct Mesh *me, const struct BMeshFromMeshParams *params)
ATTR_NONNULL(1, 3);
struct BMeshToMeshParams {
@@ -61,7 +63,11 @@ struct BMeshToMeshParams {
uint update_shapekey_indices : 1;
struct CustomData_MeshMasks cd_mask_extra;
};
+
+void BM_enter_multires_space(struct Object *ob, struct BMesh *bm, int space);
+
void BM_mesh_bm_to_me(struct Main *bmain,
+ struct Object *ob,
BMesh *bm,
struct Mesh *me,
const struct BMeshToMeshParams *params) ATTR_NONNULL(2, 3, 4);
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index bccac006e8e..1bef0ad2650 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -1064,6 +1064,21 @@ static BMOpDefine bmo_extrude_face_region_def = {
(BMO_OPTYPE_FLAG_NORMALS_CALC),
};
+extern void bmo_test_mres_smooth_exec(BMesh *bm, BMOperator *op);
+
+static BMOpDefine bmo_test_mres_smooth_def = {
+ "test_mres_smooth",
+ /* slots_in */
+ {{{'\0'}}}, /* no input */
+ {{{'\0'}}}, /* no output */
+ bmo_test_mres_smooth_exec,
+ (
+ BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE)
+};
+
/*
* Dissolve Verts.
*/
@@ -1909,7 +1924,7 @@ static BMOpDefine bmo_inset_individual_def = {
},
bmo_inset_individual_exec,
/* caller needs to handle BMO_OPTYPE_FLAG_SELECT_FLUSH */
- (BMO_OPTYPE_FLAG_NORMALS_CALC),
+ (BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_UNTAN_MULTIRES),
};
/*
@@ -1938,7 +1953,7 @@ static BMOpDefine bmo_inset_region_def = {
},
bmo_inset_region_exec,
(BMO_OPTYPE_FLAG_NORMALS_CALC |
- BMO_OPTYPE_FLAG_SELECT_FLUSH),
+ BMO_OPTYPE_FLAG_SELECT_FLUSH | BMO_OPTYPE_FLAG_UNTAN_MULTIRES),
};
/*
@@ -1959,7 +1974,7 @@ static BMOpDefine bmo_offset_edgeloops_def = {
},
bmo_offset_edgeloops_exec,
(BMO_OPTYPE_FLAG_NORMALS_CALC |
- BMO_OPTYPE_FLAG_SELECT_FLUSH),
+ BMO_OPTYPE_FLAG_SELECT_FLUSH | BMO_OPTYPE_FLAG_UNTAN_MULTIRES),
};
/*
@@ -2178,6 +2193,7 @@ const BMOpDefine *bmo_opdefines[] = {
&bmo_unsubdivide_def,
&bmo_weld_verts_def,
&bmo_wireframe_def,
+ &bmo_test_mres_smooth_def
};
const int bmo_opdefines_total = ARRAY_SIZE(bmo_opdefines);
diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c
index 4ae2cc67140..9beeb5c900b 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.c
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -1449,25 +1449,6 @@ void BM_face_splits_check_optimal(BMFace *f, BMLoop *(*loops)[2], int len)
}
/**
- * Small utility functions for fast access
- *
- * faster alternative to:
- * BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void **)v, 3);
- */
-void BM_face_as_array_vert_tri(BMFace *f, BMVert *r_verts[3])
-{
- BMLoop *l = BM_FACE_FIRST_LOOP(f);
-
- BLI_assert(f->len == 3);
-
- r_verts[0] = l->v;
- l = l->next;
- r_verts[1] = l->v;
- l = l->next;
- r_verts[2] = l->v;
-}
-
-/**
* faster alternative to:
* BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void **)v, 4);
*/
@@ -1486,24 +1467,6 @@ void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4])
r_verts[3] = l->v;
}
-/**
- * Small utility functions for fast access
- *
- * faster alternative to:
- * BM_iter_as_array(bm, BM_LOOPS_OF_FACE, f, (void **)l, 3);
- */
-void BM_face_as_array_loop_tri(BMFace *f, BMLoop *r_loops[3])
-{
- BMLoop *l = BM_FACE_FIRST_LOOP(f);
-
- BLI_assert(f->len == 3);
-
- r_loops[0] = l;
- l = l->next;
- r_loops[1] = l;
- l = l->next;
- r_loops[2] = l;
-}
/**
* faster alternative to:
diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h
index 8c2b9ee0bff..03cb5ae4bee 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.h
+++ b/source/blender/bmesh/intern/bmesh_polygon.h
@@ -23,6 +23,7 @@
struct Heap;
#include "BLI_compiler_attrs.h"
+#include "BLI_compiler_compat.h"
void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptris_tot);
void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptris_tot);
@@ -105,11 +106,47 @@ void BM_face_triangulate(BMesh *bm,
void BM_face_splits_check_legal(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len) ATTR_NONNULL();
void BM_face_splits_check_optimal(BMFace *f, BMLoop *(*loops)[2], int len) ATTR_NONNULL();
-void BM_face_as_array_vert_tri(BMFace *f, BMVert *r_verts[3]) ATTR_NONNULL();
-void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4]) ATTR_NONNULL();
+/**
+ * Small utility functions for fast access
+ *
+ * faster alternative to:
+ * BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void **)v, 3);
+ */
+BLI_INLINE void BM_face_as_array_vert_tri(BMFace *f, BMVert *r_verts[3])
+{
+ BMLoop *l = BM_FACE_FIRST_LOOP(f);
+
+ BLI_assert(f->len == 3);
+
+ r_verts[0] = l->v;
+ l = l->next;
+ r_verts[1] = l->v;
+ l = l->next;
+ r_verts[2] = l->v;
+}
+
+/**
+ * Small utility functions for fast access
+ *
+ * faster alternative to:
+ * BM_iter_as_array(bm, BM_LOOPS_OF_FACE, f, (void **)l, 3);
+ */
+BLI_INLINE void BM_face_as_array_loop_tri(BMFace *f, BMLoop *r_loops[3])
+{
+ BMLoop *l = BM_FACE_FIRST_LOOP(f);
+
+ BLI_assert(f->len == 3);
+
+ r_loops[0] = l;
+ l = l->next;
+ r_loops[1] = l;
+ l = l->next;
+ r_loops[2] = l;
+}
-void BM_face_as_array_loop_tri(BMFace *f, BMLoop *r_loops[3]) ATTR_NONNULL();
void BM_face_as_array_loop_quad(BMFace *f, BMLoop *r_loops[4]) ATTR_NONNULL();
void BM_vert_tri_calc_tangent_edge(BMVert *verts[3], float r_tangent[3]);
void BM_vert_tri_calc_tangent_edge_pair(BMVert *verts[3], float r_tangent[3]);
+
+void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4]);
diff --git a/source/blender/bmesh/operators/bmo_mesh_convert.c b/source/blender/bmesh/operators/bmo_mesh_convert.c
index e480db64f9d..d4d8c4d0806 100644
--- a/source/blender/bmesh/operators/bmo_mesh_convert.c
+++ b/source/blender/bmesh/operators/bmo_mesh_convert.c
@@ -39,7 +39,8 @@ void bmo_mesh_to_bmesh_exec(BMesh *bm, BMOperator *op)
Mesh *me = BMO_slot_ptr_get(op->slots_in, "mesh");
bool set_key = BMO_slot_bool_get(op->slots_in, "use_shapekey");
- BM_mesh_bm_from_me(bm,
+ BM_mesh_bm_from_me(NULL,
+ bm,
me,
(&(struct BMeshFromMeshParams){
.use_shapekey = set_key,
@@ -66,6 +67,7 @@ void bmo_bmesh_to_mesh_exec(BMesh *bm, BMOperator *op)
/* Object *ob = BMO_slot_ptr_get(op, "object"); */
BM_mesh_bm_to_me(G.main,
+ NULL,
bm,
me,
(&(struct BMeshToMeshParams){
diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h
index 2d5b93f4272..f1171201a4e 100644
--- a/source/blender/draw/DRW_engine.h
+++ b/source/blender/draw/DRW_engine.h
@@ -40,6 +40,9 @@ struct GHash;
struct GPUMaterial;
struct GPUOffScreen;
struct GPUViewport;
+struct GPUVertFormat;
+struct CustomData;
+struct CustomDataLayer;
struct ID;
struct Main;
struct Object;
@@ -80,6 +83,10 @@ typedef bool (*DRW_ObjectFilterFn)(struct Object *ob, void *user_data);
void DRW_draw_view(const struct bContext *C);
void DRW_draw_region_engine_info(int xoffset, int *yoffset, int line_height);
+void DRW_make_cdlayer_attr_aliases(struct GPUVertFormat *format,
+ char *base_name,
+ struct CustomData *data,
+ struct CustomDataLayer *cl);
void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
struct RenderEngineType *engine_type,
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index f902a95a19a..739723b3af0 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -37,6 +37,7 @@
#include "BKE_object.h"
#include "BKE_paint.h"
+#include "BKE_customdata.h"
#include "GPU_batch.h"
#include "GPU_batch_utils.h"
@@ -484,6 +485,40 @@ static void sphere_lat_lon_vert(GPUVertBuf *vbo, int *v_ofs, float lat, float lo
(*v_ofs)++;
}
+void DRW_make_cdlayer_attr_aliases(GPUVertFormat *format, char *base_name, CustomData *data, CustomDataLayer *cl)
+{
+ char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
+ const char *layer_name = cl->name;
+
+ int i = (int) (cl - data->typemap[cl->type]);
+
+ GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
+
+ /* UV layer name. */
+ BLI_snprintf(attr_name, sizeof(attr_name), "%s%s", base_name, attr_safe_name);
+ GPU_vertformat_alias_add(format, attr_name);
+
+ /* Auto layer name. */
+ BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
+ GPU_vertformat_alias_add(format, attr_name);
+
+ /* Active render layer name. */
+ if (i == CustomData_get_render_layer(data, cl->type)) {
+ GPU_vertformat_alias_add(format, base_name);
+ }
+ /* Active display layer name. */
+ if (i == CustomData_get_active_layer(data, cl->type)) {
+ BLI_snprintf(attr_name, sizeof(attr_name), "a%s", base_name);
+ GPU_vertformat_alias_add(format, attr_name);
+ }
+
+ /* Stencil mask uv layer name. */
+ if (i == CustomData_get_stencil_layer(data, cl->type)) {
+ BLI_snprintf(attr_name, sizeof(attr_name), "m%s", base_name);
+ GPU_vertformat_alias_add(format, attr_name);
+ }
+}
+
GPUBatch *DRW_cache_sphere_get(const eDRWLevelOfDetail level_of_detail)
{
BLI_assert(level_of_detail >= DRW_LOD_LOW && level_of_detail < DRW_LOD_MAX);
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index beb22d43930..8b4ded81b34 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -743,7 +743,6 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
brush.sculpt.cloth
brush.sculpt.crease
brush.sculpt.displacement_eraser
- brush.sculpt.displacement_smear
brush.sculpt.draw
brush.sculpt.draw_face_sets
brush.sculpt.draw_sharp
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index f0a4b3c462e..f5c501b8cff 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -919,6 +919,8 @@ DEF_ICON_COLOR(BRUSH_TEXFILL)
DEF_ICON_COLOR(BRUSH_TEXMASK)
DEF_ICON_COLOR(BRUSH_THUMB)
DEF_ICON_COLOR(BRUSH_ROTATE)
+DEF_ICON_COLOR(BRUSH_VCOL_BOUNDARY)
+DEF_ICON_COLOR(BRUSH_PAINT)
/* grease pencil sculpt */
DEF_ICON_COLOR(GPBRUSH_SMOOTH)
diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
index 7d849c096e7..6353bba1e97 100644
--- a/source/blender/editors/mesh/editmesh_mask_extract.c
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -120,7 +120,7 @@ static int geometry_extract_apply(bContext *C,
.use_toolflags = true,
}));
- BM_mesh_bm_from_me(bm,
+ BM_mesh_bm_from_me(NULL, bm,
new_mesh,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
@@ -513,7 +513,7 @@ static int paint_mask_slice_exec(bContext *C, wmOperator *op)
.use_toolflags = true,
}));
- BM_mesh_bm_from_me(bm,
+ BM_mesh_bm_from_me(NULL, bm,
new_mesh,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
@@ -544,7 +544,7 @@ static int paint_mask_slice_exec(bContext *C, wmOperator *op)
.use_toolflags = true,
}));
- BM_mesh_bm_from_me(bm,
+ BM_mesh_bm_from_me(NULL, bm,
new_ob_mesh,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 68ac2842bab..88151b07fb9 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -4208,7 +4208,7 @@ static Base *mesh_separate_tagged(
BM_mesh_normals_update(bm_new);
- BM_mesh_bm_to_me(bmain, bm_new, base_new->object->data, (&(struct BMeshToMeshParams){0}));
+ BM_mesh_bm_to_me(bmain, base_new->object, bm_new, base_new->object->data, (&(struct BMeshToMeshParams){0}));
BM_mesh_free(bm_new);
((Mesh *)base_new->object->data)->edit_mesh = NULL;
@@ -4274,7 +4274,7 @@ static Base *mesh_separate_arrays(Main *bmain,
BM_vert_kill(bm_old, verts[i]);
}
- BM_mesh_bm_to_me(bmain, bm_new, base_new->object->data, (&(struct BMeshToMeshParams){0}));
+ BM_mesh_bm_to_me(bmain, base_new->object, bm_new, base_new->object->data, (&(struct BMeshToMeshParams){0}));
BM_mesh_free(bm_new);
((Mesh *)base_new->object->data)->edit_mesh = NULL;
@@ -4456,7 +4456,7 @@ static bool mesh_separate_loose(
BM_mesh_elem_hflag_disable_all(bm_old, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
if (clear_object_data) {
- BM_mesh_bm_to_me(NULL,
+ BM_mesh_bm_to_me(NULL, base_old->object,
bm_old,
me_old,
(&(struct BMeshToMeshParams){
@@ -4543,7 +4543,7 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
.use_toolflags = true,
}));
- BM_mesh_bm_from_me(bm_old, me, (&(struct BMeshFromMeshParams){0}));
+ BM_mesh_bm_from_me(NULL, bm_old, me, (&(struct BMeshFromMeshParams){0}));
switch (type) {
case MESH_SEPARATE_MATERIAL:
@@ -4559,6 +4559,7 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
if (retval_iter) {
BM_mesh_bm_to_me(bmain,
+ ob,
bm_old,
me,
(&(struct BMeshToMeshParams){
@@ -5710,7 +5711,7 @@ static void edbm_dissolve_prop__use_boundary_tear(wmOperatorType *ot)
"Split off face corners instead of merging faces");
}
-static int edbm_dissolve_verts_exec(bContext *C, wmOperator *op)
+static int edbm_mres_test_exec(bContext *C, wmOperator *op)
{
const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split");
const bool use_boundary_tear = RNA_boolean_get(op->ptr, "use_boundary_tear");
@@ -5732,10 +5733,116 @@ static int edbm_dissolve_verts_exec(bContext *C, wmOperator *op)
if (!EDBM_op_callf(em,
op,
- "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
- BM_ELEM_SELECT,
- use_face_split,
- use_boundary_tear)) {
+ "test_mres_smooth")) {
+ continue;
+ }
+
+ BM_custom_loop_normals_from_vector_layer(em->bm, false);
+ EDBM_update_generic(obedit->data, true, true);
+ }
+
+ MEM_freeN(objects);
+ return OPERATOR_FINISHED;
+}
+
+
+extern Object *multires_dump_grids_bmesh(Object *bmob, BMesh *bm);
+
+static int edbm_dump_mres_grids_exec(bContext *C, wmOperator *op)
+{
+ const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split");
+ const bool use_boundary_tear = RNA_boolean_get(op->ptr, "use_boundary_tear");
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ multires_dump_grids_bmesh(obedit, em->bm);
+ }
+
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C));
+
+ MEM_freeN(objects);
+ return OPERATOR_FINISHED;
+}
+
+static bool mres_test_poll(bContext *C)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ if (obedit && obedit->type == OB_MESH) {
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (!em || !CustomData_has_layer(&em->bm->ldata, CD_MDISPS)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+void MESH_OT_dump_mres_grids(wmOperatorType *ot) {
+ /* identifiers */
+ ot->name = "Dump Multires Grids";
+ ot->description = "Dump Multires Grids";
+ ot->idname = "MESH_OT_dump_mres_grids";
+
+ /* api callbacks */
+ ot->exec = edbm_dump_mres_grids_exec;
+ ot->poll = mres_test_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+void MESH_OT_mres_test(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Test Multires Boundary Smooth";
+ ot->description = "Test multires boundary smooth";
+ ot->idname = "MESH_OT_mres_test";
+
+ /* api callbacks */
+ ot->exec = edbm_mres_test_exec;
+ ot->poll = mres_test_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+static int edbm_dissolve_verts_exec(bContext *C, wmOperator *op)
+{
+ const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split");
+ const bool use_boundary_tear = RNA_boolean_get(op->ptr, "use_boundary_tear");
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (em->bm->totvertsel == 0) {
+ continue;
+ }
+
+ BM_custom_loop_normals_to_vector_layer(em->bm);
+
+ if (!EDBM_op_callf(em,
+ op,
+ "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
+ BM_ELEM_SELECT,
+ use_face_split,
+ use_boundary_tear)) {
continue;
}
@@ -5748,6 +5855,7 @@ static int edbm_dissolve_verts_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+
void MESH_OT_dissolve_verts(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index 79385e28aa9..d40bd790122 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -545,7 +545,7 @@ static void *undomesh_from_editmesh(UndoMesh *um, BMEditMesh *em, Key *key)
/* BM_mesh_validate(em->bm); */ /* for troubleshooting */
BM_mesh_bm_to_me(
- NULL,
+ NULL, NULL,
em->bm,
&um->me,
(&(struct BMeshToMeshParams){
@@ -621,7 +621,7 @@ static void undomesh_to_editmesh(UndoMesh *um, Object *ob, BMEditMesh *em, Key *
.use_toolflags = true,
}));
- BM_mesh_bm_from_me(bm,
+ BM_mesh_bm_from_me(NULL, bm,
&um->me,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 94f386e08d5..ce77f90c5fe 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -352,6 +352,7 @@ void EDBM_mesh_load_ex(Main *bmain, Object *ob, bool free_data)
}
BM_mesh_bm_to_me(bmain,
+ ob,
bm,
me,
(&(struct BMeshToMeshParams){
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 21feddfb886..fcef1866e3a 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -259,6 +259,7 @@ void MESH_OT_set_normals_from_faces(struct wmOperatorType *ot);
void MESH_OT_average_normals(struct wmOperatorType *ot);
void MESH_OT_smooth_normals(struct wmOperatorType *ot);
void MESH_OT_mod_weighted_strength(struct wmOperatorType *ot);
+void MESH_OT_mres_test(struct wmOperatorType *ot);
/* *** editmesh_mask_extract.c *** */
void MESH_OT_paint_mask_extract(struct wmOperatorType *ot);
@@ -285,3 +286,4 @@ void MESH_OT_customdata_skin_add(struct wmOperatorType *ot);
void MESH_OT_customdata_skin_clear(struct wmOperatorType *ot);
void MESH_OT_customdata_custom_splitnormals_add(struct wmOperatorType *ot);
void MESH_OT_customdata_custom_splitnormals_clear(struct wmOperatorType *ot);
+void MESH_OT_dump_mres_grids(struct wmOperatorType *ot);
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index 27d73497b49..46c744085cc 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -205,6 +205,9 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_average_normals);
WM_operatortype_append(MESH_OT_smooth_normals);
WM_operatortype_append(MESH_OT_mod_weighted_strength);
+ WM_operatortype_append(MESH_OT_mres_test);
+ WM_operatortype_append(MESH_OT_dump_mres_grids);
+
}
#if 0 /* UNUSED, remove? */
diff --git a/source/blender/editors/object/object_remesh.c b/source/blender/editors/object/object_remesh.c
index 9ef2cce875f..2faa1a7d401 100644
--- a/source/blender/editors/object/object_remesh.c
+++ b/source/blender/editors/object/object_remesh.c
@@ -754,7 +754,7 @@ static void quadriflow_update_job(void *customdata, float progress, int *cancel)
*(qj->progress) = progress;
}
-static Mesh *remesh_symmetry_bisect(Mesh *mesh, eSymmetryAxes symmetry_axes)
+static Mesh *remesh_symmetry_bisect(Object *ob, Mesh *mesh, eSymmetryAxes symmetry_axes)
{
MirrorModifierData mmd = {{0}};
mmd.tolerance = QUADRIFLOW_MIRROR_BISECT_TOLERANCE;
@@ -775,8 +775,10 @@ static Mesh *remesh_symmetry_bisect(Mesh *mesh, eSymmetryAxes symmetry_axes)
zero_v3(plane_no);
plane_no[axis] = -1.0f;
mesh_bisect_temp = mesh_bisect;
- mesh_bisect = BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(
+
+ mesh_bisect = BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(ob,
&mmd, mesh_bisect, axis, plane_co, plane_no);
+
if (mesh_bisect_temp != mesh_bisect) {
BKE_id_free(NULL, mesh_bisect_temp);
}
@@ -844,7 +846,7 @@ static void quadriflow_start_job(void *customdata, short *stop, short *do_update
bisect_mesh = BKE_mesh_copy_for_eval(mesh, false);
/* Bisect the input mesh using the paint symmetry settings */
- bisect_mesh = remesh_symmetry_bisect(bisect_mesh, qj->symmetry_axes);
+ bisect_mesh = remesh_symmetry_bisect(ob, bisect_mesh, qj->symmetry_axes);
new_mesh = BKE_mesh_remesh_quadriflow_to_mesh_nomain(
bisect_mesh,
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index fff172c0707..e4996e8196b 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -56,6 +56,7 @@ set(SRC
paint_vertex_weight_ops.c
paint_vertex_weight_utils.c
sculpt.c
+ sculpt_curvature.c
sculpt_automasking.c
sculpt_boundary.c
sculpt_cloth.c
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index b44f2f66d92..c76fa01816b 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -1214,7 +1214,7 @@ typedef struct PaintCursorContext {
/* Sculpt related data. */
Sculpt *sd;
SculptSession *ss;
- int prev_active_vertex_index;
+ SculptVertRef prev_active_vertex_index;
bool is_stroke_active;
bool is_cursor_over_mesh;
bool is_multires;
@@ -1573,8 +1573,8 @@ static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext *
paint_cursor_update_object_space_radius(pcontext);
- const bool update_previews = pcontext->prev_active_vertex_index !=
- SCULPT_active_vertex_get(pcontext->ss);
+ const bool update_previews = pcontext->prev_active_vertex_index.i !=
+ SCULPT_active_vertex_get(pcontext->ss).i;
/* Setup drawing. */
wmViewport(&pcontext->region->winrct);
diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c
index da627c6b7db..4e3e074c9bf 100644
--- a/source/blender/editors/sculpt_paint/paint_hide.c
+++ b/source/blender/editors/sculpt_paint/paint_hide.c
@@ -209,17 +209,15 @@ static void partialvis_update_grids(Depsgraph *depsgraph,
}
static void partialvis_update_bmesh_verts(BMesh *bm,
- GSet *verts,
+ TableGSet *verts,
PartialVisAction action,
PartialVisArea area,
float planes[4][4],
bool *any_changed,
bool *any_visible)
{
- GSetIterator gs_iter;
-
- GSET_ITER (gs_iter, verts) {
- BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
+ BMVert *v;
+ TGSET_ITER (v, verts) {
float *vmask = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_PAINT_MASK);
/* Hide vertex if in the hide volume. */
@@ -237,15 +235,14 @@ static void partialvis_update_bmesh_verts(BMesh *bm,
(*any_visible) = true;
}
}
+ TGSET_ITER_END
}
-static void partialvis_update_bmesh_faces(GSet *faces)
+static void partialvis_update_bmesh_faces(TableGSet *faces)
{
- GSetIterator gs_iter;
-
- GSET_ITER (gs_iter, faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+ BMFace *f;
+ TGSET_ITER (f, faces) {
if (paint_is_bmesh_face_hidden(f)) {
BM_elem_flag_enable(f, BM_ELEM_HIDDEN);
}
@@ -253,6 +250,7 @@ static void partialvis_update_bmesh_faces(GSet *faces)
BM_elem_flag_disable(f, BM_ELEM_HIDDEN);
}
}
+ TGSET_ITER_END
}
static void partialvis_update_bmesh(Object *ob,
@@ -263,7 +261,7 @@ static void partialvis_update_bmesh(Object *ob,
float planes[4][4])
{
BMesh *bm;
- GSet *unique, *other, *faces;
+ TableGSet *unique, *other, *faces;
bool any_changed = false, any_visible = false;
bm = BKE_pbvh_get_bmesh(pbvh);
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index 26e2bcc42cf..91c8f9fb969 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -680,7 +680,7 @@ static bool sculpt_gesture_is_effected_lasso(SculptGestureContext *sgcontext, co
static bool sculpt_gesture_is_vertex_effected(SculptGestureContext *sgcontext, PBVHVertexIter *vd)
{
float vertex_normal[3];
- SCULPT_vertex_normal_get(sgcontext->ss, vd->index, vertex_normal);
+ SCULPT_vertex_normal_get(sgcontext->ss, vd->vertex, vertex_normal);
float dot = dot_v3v3(sgcontext->view_normal, vertex_normal);
const bool is_effected_front_face = !(sgcontext->front_faces_only && dot < 0.0f);
@@ -760,7 +760,7 @@ static void face_set_gesture_apply_task_cb(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(sgcontext->ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
{
if (sculpt_gesture_is_vertex_effected(sgcontext, &vd)) {
- SCULPT_vertex_face_set_set(sgcontext->ss, vd.index, face_set_operation->new_face_set_id);
+ SCULPT_vertex_face_set_set(sgcontext->ss, vd.vertex, face_set_operation->new_face_set_id);
any_updated = true;
}
}
@@ -977,7 +977,7 @@ static void sculpt_gesture_trim_normals_update(SculptGestureContext *sgcontext)
.use_toolflags = true,
}));
- BM_mesh_bm_from_me(bm,
+ BM_mesh_bm_from_me(NULL, bm,
trim_mesh,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
@@ -1043,7 +1043,7 @@ static void sculpt_gesture_trim_calculate_depth(SculptGestureContext *sgcontext)
trim_operation->depth_back = -FLT_MAX;
for (int i = 0; i < totvert; i++) {
- const float *vco = SCULPT_vertex_co_get(ss, i);
+ const float *vco = SCULPT_vertex_co_get(ss, BKE_pbvh_table_index_to_vertex(ss->pbvh, i));
/* Convert the coordinates to world space to calculate the depth. When generating the trimming
* mesh, coordinates are first calculated in world space, then converted to object space to
* store them. */
@@ -1229,13 +1229,15 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext)
.use_toolflags = false,
}));
- BM_mesh_bm_from_me(bm,
+ BM_mesh_bm_from_me(NULL,
+ bm,
trim_mesh,
&((struct BMeshFromMeshParams){
.calc_face_normal = true,
}));
- BM_mesh_bm_from_me(bm,
+ BM_mesh_bm_from_me(NULL,
+ bm,
sculpt_mesh,
&((struct BMeshFromMeshParams){
.calc_face_normal = true,
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 631327ddfe8..4bb9bcfdc0a 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -117,7 +117,7 @@
void SCULPT_vertex_random_access_ensure(SculptSession *ss)
{
- if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ if (ss->bm) {
BM_mesh_elem_index_ensure(ss->bm, BM_VERT);
BM_mesh_elem_table_ensure(ss->bm, BM_VERT);
}
@@ -137,22 +137,24 @@ int SCULPT_vertex_count_get(SculptSession *ss)
return 0;
}
-const float *SCULPT_vertex_co_get(SculptSession *ss, int index)
+const float *SCULPT_vertex_co_get(SculptSession *ss, SculptVertRef index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
if (ss->shapekey_active || ss->deform_modifiers_active) {
const MVert *mverts = BKE_pbvh_get_verts(ss->pbvh);
- return mverts[index].co;
+ return mverts[index.i].co;
}
- return ss->mvert[index].co;
+ return ss->mvert[index.i].co;
+ }
+ case PBVH_BMESH: {
+ BMVert *v = (BMVert *)index.i;
+ return v->co;
}
- case PBVH_BMESH:
- return BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->co;
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
- const int grid_index = index / key->grid_area;
- const int vertex_index = index - grid_index * key->grid_area;
+ const int grid_index = index.i / key->grid_area;
+ const int vertex_index = index.i - grid_index * key->grid_area;
CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index];
return CCG_elem_co(key, CCG_elem_offset(key, elem, vertex_index));
}
@@ -160,41 +162,53 @@ const float *SCULPT_vertex_co_get(SculptSession *ss, int index)
return NULL;
}
-const float *SCULPT_vertex_color_get(SculptSession *ss, int index)
+const float *SCULPT_vertex_color_get(SculptSession *ss, SculptVertRef index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
if (ss->vcol) {
- return ss->vcol[index].color;
+ return ss->vcol[index.i].color;
}
break;
- case PBVH_BMESH:
+ case PBVH_BMESH: {
+ BMVert *v = (BMVert *)index.i;
+
+ if (ss->cd_vcol_offset >= 0) {
+ MPropCol *col = BM_ELEM_CD_GET_VOID_P(v, ss->cd_vcol_offset);
+ return col->color;
+ }
+
+ break;
+ }
case PBVH_GRIDS:
break;
}
return NULL;
}
-void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3])
+void SCULPT_vertex_normal_get(SculptSession *ss, SculptVertRef index, float no[3])
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
if (ss->shapekey_active || ss->deform_modifiers_active) {
const MVert *mverts = BKE_pbvh_get_verts(ss->pbvh);
- normal_short_to_float_v3(no, mverts[index].no);
+ normal_short_to_float_v3(no, mverts[index.i].no);
}
else {
- normal_short_to_float_v3(no, ss->mvert[index].no);
+ normal_short_to_float_v3(no, ss->mvert[index.i].no);
}
break;
}
- case PBVH_BMESH:
- copy_v3_v3(no, BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->no);
+ case PBVH_BMESH: {
+ BMVert *v = (BMVert *)index.i;
+
+ copy_v3_v3(no, v->no);
break;
+ }
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
- const int grid_index = index / key->grid_area;
- const int vertex_index = index - grid_index * key->grid_area;
+ const int grid_index = index.i / key->grid_area;
+ const int vertex_index = index.i - grid_index * key->grid_area;
CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index];
copy_v3_v3(no, CCG_elem_no(key, CCG_elem_offset(key, elem, vertex_index)));
break;
@@ -202,32 +216,35 @@ void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3])
}
}
-const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, int index)
+const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, SculptVertRef index)
{
if (ss->persistent_base) {
- return ss->persistent_base[index].co;
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ index.i = BM_elem_index_get((BMVert *)index.i);
+ }
+ return ss->persistent_base[index.i].co;
}
return SCULPT_vertex_co_get(ss, index);
}
-const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, int index)
+const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, SculptVertRef vertex)
{
/* Always grab active shape key if the sculpt happens on shapekey. */
if (ss->shapekey_active) {
const MVert *mverts = BKE_pbvh_get_verts(ss->pbvh);
- return mverts[index].co;
+ return mverts[BKE_pbvh_vertex_index_to_table(ss->pbvh, vertex)].co;
}
/* Sculpting on the base mesh. */
if (ss->mvert) {
- return ss->mvert[index].co;
+ return ss->mvert[BKE_pbvh_vertex_index_to_table(ss->pbvh, vertex)].co;
}
/* Everything else, such as sculpting on multires. */
- return SCULPT_vertex_co_get(ss, index);
+ return SCULPT_vertex_co_get(ss, vertex);
}
-void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3])
+void SCULPT_vertex_limit_surface_get(SculptSession *ss, SculptVertRef index, float r_co[3])
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
@@ -236,8 +253,8 @@ void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3]
break;
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
- const int grid_index = index / key->grid_area;
- const int vertex_index = index - grid_index * key->grid_area;
+ const int grid_index = index.i / key->grid_area;
+ const int vertex_index = index.i - grid_index * key->grid_area;
SubdivCCGCoord coord = {.grid_index = grid_index,
.x = vertex_index % key->grid_size,
@@ -248,30 +265,30 @@ void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3]
}
}
-void SCULPT_vertex_persistent_normal_get(SculptSession *ss, int index, float no[3])
+void SCULPT_vertex_persistent_normal_get(SculptSession *ss, SculptVertRef index, float no[3])
{
if (ss->persistent_base) {
- copy_v3_v3(no, ss->persistent_base[index].no);
+ copy_v3_v3(no, ss->persistent_base[BKE_pbvh_vertex_index_to_table(ss->pbvh, index)].no);
return;
}
SCULPT_vertex_normal_get(ss, index, no);
}
-float SCULPT_vertex_mask_get(SculptSession *ss, int index)
+float SCULPT_vertex_mask_get(SculptSession *ss, SculptVertRef index)
{
BMVert *v;
float *mask;
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
- return ss->vmask[index];
+ return ss->vmask[index.i];
case PBVH_BMESH:
- v = BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index);
+ v = (BMVert *)index.i;
mask = BM_ELEM_CD_GET_VOID_P(v, CustomData_get_offset(&ss->bm->vdata, CD_PAINT_MASK));
return *mask;
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
- const int grid_index = index / key->grid_area;
- const int vertex_index = index - grid_index * key->grid_area;
+ const int grid_index = index.i / key->grid_area;
+ const int vertex_index = index.i - grid_index * key->grid_area;
CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index];
return *CCG_elem_mask(key, CCG_elem_offset(key, elem, vertex_index));
}
@@ -280,12 +297,12 @@ float SCULPT_vertex_mask_get(SculptSession *ss, int index)
return 0.0f;
}
-int SCULPT_active_vertex_get(SculptSession *ss)
+SculptVertRef SCULPT_active_vertex_get(SculptSession *ss)
{
if (ELEM(BKE_pbvh_type(ss->pbvh), PBVH_FACES, PBVH_BMESH, PBVH_GRIDS)) {
return ss->active_vertex_index;
}
- return 0;
+ return BKE_pbvh_make_vref(0);
}
const float *SCULPT_active_vertex_co_get(SculptSession *ss)
@@ -338,44 +355,49 @@ int SCULPT_active_face_set_get(SculptSession *ss)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
- return ss->face_sets[ss->active_face_index];
+ return ss->face_sets[ss->active_face_index.i];
case PBVH_GRIDS: {
const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg,
ss->active_grid_index);
return ss->face_sets[face_index];
}
case PBVH_BMESH:
+ if (ss->cd_faceset_offset && ss->active_face_index.i) {
+ BMFace *f = (BMFace *)ss->active_face_index.i;
+ return BM_ELEM_CD_GET_INT(f, ss->cd_faceset_offset);
+ }
+
return SCULPT_FACE_SET_NONE;
}
return SCULPT_FACE_SET_NONE;
}
-void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible)
+void SCULPT_vertex_visible_set(SculptSession *ss, SculptVertRef index, bool visible)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
- SET_FLAG_FROM_TEST(ss->mvert[index].flag, !visible, ME_HIDE);
- ss->mvert[index].flag |= ME_VERT_PBVH_UPDATE;
+ SET_FLAG_FROM_TEST(ss->mvert[index.i].flag, !visible, ME_HIDE);
+ ss->mvert[index.i].flag |= ME_VERT_PBVH_UPDATE;
break;
case PBVH_BMESH:
- BM_elem_flag_set(BM_vert_at_index(ss->bm, index), BM_ELEM_HIDDEN, !visible);
+ BM_elem_flag_set((BMVert *)index.i, BM_ELEM_HIDDEN, !visible);
break;
case PBVH_GRIDS:
break;
}
}
-bool SCULPT_vertex_visible_get(SculptSession *ss, int index)
+bool SCULPT_vertex_visible_get(SculptSession *ss, SculptVertRef index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
- return !(ss->mvert[index].flag & ME_HIDE);
+ return !(ss->mvert[index.i].flag & ME_HIDE);
case PBVH_BMESH:
- return !BM_elem_flag_test(BM_vert_at_index(ss->bm, index), BM_ELEM_HIDDEN);
+ return !BM_elem_flag_test(((BMVert *)index.i), BM_ELEM_HIDDEN);
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
- const int grid_index = index / key->grid_area;
- const int vertex_index = index - grid_index * key->grid_area;
+ const int grid_index = index.i / key->grid_area;
+ const int vertex_index = index.i - grid_index * key->grid_area;
BLI_bitmap **grid_hidden = BKE_pbvh_get_grid_visibility(ss->pbvh);
if (grid_hidden && grid_hidden[grid_index]) {
return !BLI_BITMAP_TEST(grid_hidden[grid_index], vertex_index);
@@ -402,8 +424,28 @@ void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visibl
}
}
break;
- case PBVH_BMESH:
+ case PBVH_BMESH: {
+ BMIter iter;
+ BMFace *f;
+
+ BM_ITER_MESH (f, &iter, ss->bm, BM_FACES_OF_MESH) {
+ int fset = BM_ELEM_CD_GET_INT(f, ss->cd_faceset_offset);
+
+ if (abs(fset) != face_set) {
+ continue;
+ }
+
+ if (visible) {
+ fset = abs(fset);
+ }
+ else {
+ fset = -abs(fset);
+ }
+
+ BM_ELEM_CD_SET_INT(f, ss->cd_faceset_offset, fset);
+ }
break;
+ }
}
}
@@ -416,8 +458,19 @@ void SCULPT_face_sets_visibility_invert(SculptSession *ss)
ss->face_sets[i] *= -1;
}
break;
- case PBVH_BMESH:
+ case PBVH_BMESH: {
+ BMIter iter;
+ BMFace *f;
+
+ BM_ITER_MESH (f, &iter, ss->bm, BM_FACES_OF_MESH) {
+ int fset = BM_ELEM_CD_GET_INT(f, ss->cd_faceset_offset);
+
+ fset = -fset;
+
+ BM_ELEM_CD_SET_INT(f, ss->cd_faceset_offset, fset);
+ }
break;
+ }
}
}
@@ -443,48 +496,108 @@ void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible)
}
}
break;
- case PBVH_BMESH:
+ case PBVH_BMESH: {
+ BMIter iter;
+ BMFace *f;
+
+ if (!ss->bm) {
+ return;
+ }
+
+ // paranoia check of cd_faceset_offset
+ if (ss->cd_faceset_offset < 0) {
+ ss->cd_faceset_offset = CustomData_get_offset(&ss->bm->pdata, CD_SCULPT_FACE_SETS);
+ }
+ if (ss->cd_faceset_offset < 0) {
+ return;
+ }
+
+ BM_ITER_MESH (f, &iter, ss->bm, BM_FACES_OF_MESH) {
+ int fset = BM_ELEM_CD_GET_INT(f, ss->cd_faceset_offset);
+
+ /* This can run on geometry without a face set assigned, so its ID sign can't be changed to
+ * modify the visibility. Force that geometry to the ID 1 to enable changing the visibility
+ * here. */
+
+ if (fset == SCULPT_FACE_SET_NONE) {
+ fset = 1;
+ }
+
+ if (visible) {
+ fset = abs(fset);
+ }
+ else {
+ fset = -abs(fset);
+ }
+
+ BM_ELEM_CD_SET_INT(f, ss->cd_faceset_offset, fset);
+ }
break;
+ }
}
}
-bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index)
+bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, SculptVertRef index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
- MeshElemMap *vert_map = &ss->pmap[index];
- for (int j = 0; j < ss->pmap[index].count; j++) {
+ MeshElemMap *vert_map = &ss->pmap[index.i];
+ for (int j = 0; j < ss->pmap[index.i].count; j++) {
if (ss->face_sets[vert_map->indices[j]] > 0) {
return true;
}
}
return false;
}
- case PBVH_BMESH:
- return true;
+ case PBVH_BMESH: {
+ BMIter iter;
+ BMLoop *l;
+ BMVert *v = (BMVert *)index.i;
+
+ BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
+ int fset = BM_ELEM_CD_GET_INT(l->f, ss->cd_faceset_offset);
+ if (fset >= 0) {
+ return true;
+ }
+ }
+
+ return false;
+ }
case PBVH_GRIDS:
return true;
}
return true;
}
-bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index)
+bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, SculptVertRef index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
- MeshElemMap *vert_map = &ss->pmap[index];
- for (int j = 0; j < ss->pmap[index].count; j++) {
+ MeshElemMap *vert_map = &ss->pmap[index.i];
+ for (int j = 0; j < ss->pmap[index.i].count; j++) {
if (ss->face_sets[vert_map->indices[j]] < 0) {
return false;
}
}
return true;
}
- case PBVH_BMESH:
+ case PBVH_BMESH: {
+ BMIter iter;
+ BMLoop *l;
+ BMVert *v = (BMVert *)index.i;
+
+ BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
+ int fset = BM_ELEM_CD_GET_INT(l->f, ss->cd_faceset_offset);
+ if (fset < 0) {
+ return false;
+ }
+ }
+
return true;
+ }
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
- const int grid_index = index / key->grid_area;
+ const int grid_index = index.i / key->grid_area;
const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index);
return ss->face_sets[face_index] > 0;
}
@@ -492,22 +605,34 @@ bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index)
return true;
}
-void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set)
+void SCULPT_vertex_face_set_set(SculptSession *ss, SculptVertRef index, int face_set)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
- MeshElemMap *vert_map = &ss->pmap[index];
- for (int j = 0; j < ss->pmap[index].count; j++) {
+ MeshElemMap *vert_map = &ss->pmap[index.i];
+ for (int j = 0; j < ss->pmap[index.i].count; j++) {
if (ss->face_sets[vert_map->indices[j]] > 0) {
ss->face_sets[vert_map->indices[j]] = abs(face_set);
}
}
} break;
- case PBVH_BMESH:
+ case PBVH_BMESH: {
+ BMIter iter;
+ BMLoop *l;
+ BMVert *v = (BMVert *)index.i;
+
+ BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
+ int fset = BM_ELEM_CD_GET_INT(l->f, ss->cd_faceset_offset);
+ if (fset >= 0) {
+ BM_ELEM_CD_SET_INT(l->f, ss->cd_faceset_offset, abs(face_set));
+ }
+ }
+
break;
+ }
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
- const int grid_index = index / key->grid_area;
+ const int grid_index = index.i / key->grid_area;
const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index);
if (ss->face_sets[face_index] > 0) {
ss->face_sets[face_index] = abs(face_set);
@@ -517,24 +642,39 @@ void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set)
}
}
-int SCULPT_vertex_face_set_get(SculptSession *ss, int index)
+int SCULPT_vertex_face_set_get(SculptSession *ss, SculptVertRef index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
- MeshElemMap *vert_map = &ss->pmap[index];
+ MeshElemMap *vert_map = &ss->pmap[index.i];
int face_set = 0;
- for (int i = 0; i < ss->pmap[index].count; i++) {
+ for (int i = 0; i < ss->pmap[index.i].count; i++) {
if (ss->face_sets[vert_map->indices[i]] > face_set) {
face_set = abs(ss->face_sets[vert_map->indices[i]]);
}
}
return face_set;
}
- case PBVH_BMESH:
- return 0;
+ case PBVH_BMESH: {
+ BMIter iter;
+ BMLoop *l;
+ BMVert *v = (BMVert *)index.i;
+ int ret = -1;
+
+ BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
+ int fset = BM_ELEM_CD_GET_INT(l->f, ss->cd_faceset_offset);
+ fset = abs(fset);
+
+ if (fset > ret) {
+ ret = fset;
+ }
+ }
+
+ return ret < 0 ? 0 : ret;
+ }
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
- const int grid_index = index / key->grid_area;
+ const int grid_index = index.i / key->grid_area;
const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index);
return ss->face_sets[face_index];
}
@@ -542,23 +682,40 @@ int SCULPT_vertex_face_set_get(SculptSession *ss, int index)
return 0;
}
-bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set)
+bool SCULPT_vertex_has_face_set(SculptSession *ss, SculptVertRef index, int face_set)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
- MeshElemMap *vert_map = &ss->pmap[index];
- for (int i = 0; i < ss->pmap[index].count; i++) {
+ MeshElemMap *vert_map = &ss->pmap[index.i];
+ for (int i = 0; i < ss->pmap[index.i].count; i++) {
if (ss->face_sets[vert_map->indices[i]] == face_set) {
return true;
}
}
return false;
}
- case PBVH_BMESH:
- return true;
+ case PBVH_BMESH: {
+ BMIter iter;
+ BMLoop *l;
+ BMVert *v = (BMVert *)index.i;
+
+ if (ss->cd_faceset_offset == -1) {
+ return false;
+ }
+
+ BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
+ BMFace *f = l->f;
+
+ if (abs(BM_ELEM_CD_GET_INT(f, ss->cd_faceset_offset)) == abs(face_set)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
- const int grid_index = index / key->grid_area;
+ const int grid_index = index.i / key->grid_area;
const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index);
return ss->face_sets[face_index] == face_set;
}
@@ -580,16 +737,54 @@ void SCULPT_visibility_sync_all_face_sets_to_vertices(Object *ob)
BKE_sculpt_sync_face_sets_visibility_to_grids(mesh, ss->subdiv_ccg);
break;
}
- case PBVH_BMESH:
+ case PBVH_BMESH: {
+ BMIter iter;
+ BMFace *f;
+ BMVert *v;
+
+ BM_ITER_MESH (f, &iter, ss->bm, BM_FACES_OF_MESH) {
+ int fset = BM_ELEM_CD_GET_INT(f, ss->cd_faceset_offset);
+
+ if (fset < 0) {
+ BM_elem_flag_enable(f, BM_ELEM_HIDDEN);
+ }
+ else {
+ BM_elem_flag_disable(f, BM_ELEM_HIDDEN);
+ }
+ }
+
+ BM_ITER_MESH (v, &iter, ss->bm, BM_VERTS_OF_MESH) {
+ BMIter iter2;
+ BMLoop *l;
+
+ int visible = false;
+
+ BM_ITER_ELEM (l, &iter2, v, BM_LOOPS_OF_VERT) {
+ if (!BM_elem_flag_test(l->f, BM_ELEM_HIDDEN)) {
+ visible = true;
+ break;
+ }
+ }
+
+ if (!visible) {
+ BM_elem_flag_enable(v, BM_ELEM_HIDDEN);
+ }
+ else {
+ BM_elem_flag_disable(v, BM_ELEM_HIDDEN);
+ }
+ }
break;
+ }
}
}
static void UNUSED_FUNCTION(sculpt_visibility_sync_vertex_to_face_sets)(SculptSession *ss,
- int index)
+ SculptVertRef vertex)
{
+ int index = (int)vertex.i;
MeshElemMap *vert_map = &ss->pmap[index];
- const bool visible = SCULPT_vertex_visible_get(ss, index);
+ const bool visible = SCULPT_vertex_visible_get(ss, vertex);
+
for (int i = 0; i < ss->pmap[index].count; i++) {
if (visible) {
ss->face_sets[vert_map->indices[i]] = abs(ss->face_sets[vert_map->indices[i]]);
@@ -603,28 +798,68 @@ static void UNUSED_FUNCTION(sculpt_visibility_sync_vertex_to_face_sets)(SculptSe
void SCULPT_visibility_sync_all_vertex_to_face_sets(SculptSession *ss)
{
- if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
- for (int i = 0; i < ss->totfaces; i++) {
- MPoly *poly = &ss->mpoly[i];
- bool poly_visible = true;
- for (int l = 0; l < poly->totloop; l++) {
- MLoop *loop = &ss->mloop[poly->loopstart + l];
- if (!SCULPT_vertex_visible_get(ss, (int)loop->v)) {
- poly_visible = false;
+ switch (BKE_pbvh_type(ss->pbvh)) {
+ case PBVH_FACES: {
+ for (int i = 0; i < ss->totfaces; i++) {
+ MPoly *poly = &ss->mpoly[i];
+ bool poly_visible = true;
+ for (int l = 0; l < poly->totloop; l++) {
+ MLoop *loop = &ss->mloop[poly->loopstart + l];
+ if (!SCULPT_vertex_visible_get(ss, BKE_pbvh_make_vref(loop->v))) {
+ poly_visible = false;
+ }
+ }
+ if (poly_visible) {
+ ss->face_sets[i] = abs(ss->face_sets[i]);
+ }
+ else {
+ ss->face_sets[i] = -abs(ss->face_sets[i]);
}
}
- if (poly_visible) {
- ss->face_sets[i] = abs(ss->face_sets[i]);
+ break;
+ }
+ case PBVH_GRIDS:
+ break;
+ case PBVH_BMESH: {
+ BMIter iter;
+ BMFace *f;
+
+ if (!ss->bm) {
+ return;
}
- else {
- ss->face_sets[i] = -abs(ss->face_sets[i]);
+
+ BM_ITER_MESH (f, &iter, ss->bm, BM_FACES_OF_MESH) {
+ BMLoop *l = f->l_first;
+ bool visible = true;
+
+ do {
+ if (BM_elem_flag_test(l->v, BM_ELEM_HIDDEN)) {
+ visible = false;
+ break;
+ }
+ l = l->next;
+ } while (l != f->l_first);
+
+ int fset = BM_ELEM_CD_GET_INT(f, ss->cd_faceset_offset);
+ if (visible) {
+ fset = abs(fset);
+ }
+ else {
+ fset = -abs(fset);
+ }
+
+ BM_ELEM_CD_SET_INT(f, ss->cd_faceset_offset, fset);
}
+
+ break;
}
}
}
-static bool sculpt_check_unique_face_set_in_base_mesh(SculptSession *ss, int index)
+static bool sculpt_check_unique_face_set_in_base_mesh(SculptSession *ss, SculptVertRef vertex)
{
+ int index = BKE_pbvh_vertex_index_to_table(ss->pbvh, vertex);
+
MeshElemMap *vert_map = &ss->pmap[index];
int face_set = -1;
for (int i = 0; i < ss->pmap[index].count; i++) {
@@ -672,18 +907,41 @@ static bool sculpt_check_unique_face_set_for_edge_in_base_mesh(SculptSession *ss
return true;
}
-bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index)
+bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, SculptVertRef index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
return sculpt_check_unique_face_set_in_base_mesh(ss, index);
}
- case PBVH_BMESH:
- return true;
+ case PBVH_BMESH: {
+ BMIter iter;
+ BMLoop *l;
+ BMVert *v = (BMVert *)index.i;
+ int face_set = 0;
+ bool first = true;
+
+ if (ss->cd_faceset_offset == -1) {
+ return false;
+ }
+
+ BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
+ BMFace *f = l->f;
+ int face_set2 = BM_ELEM_CD_GET_INT(f, ss->cd_faceset_offset);
+
+ if (!first && abs(face_set2) != abs(face_set)) {
+ return false;
+ }
+
+ first = false;
+ face_set = face_set2;
+ }
+
+ return !first;
+ }
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
- const int grid_index = index / key->grid_area;
- const int vertex_index = index - grid_index * key->grid_area;
+ const int grid_index = index.i / key->grid_area;
+ const int vertex_index = index.i - grid_index * key->grid_area;
const SubdivCCGCoord coord = {.grid_index = grid_index,
.x = vertex_index % key->grid_size,
.y = vertex_index / key->grid_size};
@@ -692,7 +950,7 @@ bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index)
ss->subdiv_ccg, &coord, ss->mloop, ss->mpoly, &v1, &v2);
switch (adjacency) {
case SUBDIV_CCG_ADJACENT_VERTEX:
- return sculpt_check_unique_face_set_in_base_mesh(ss, v1);
+ return sculpt_check_unique_face_set_in_base_mesh(ss, BKE_pbvh_make_vref(v1));
case SUBDIV_CCG_ADJACENT_EDGE:
return sculpt_check_unique_face_set_for_edge_in_base_mesh(ss, v1, v2);
case SUBDIV_CCG_ADJACENT_NONE:
@@ -717,8 +975,24 @@ int SCULPT_face_set_next_available_get(SculptSession *ss)
next_face_set++;
return next_face_set;
}
- case PBVH_BMESH:
- return 0;
+ case PBVH_BMESH: {
+ int next_face_set = 0;
+ BMIter iter;
+ BMFace *f;
+ if (!ss->cd_faceset_offset) {
+ return 0;
+ }
+
+ BM_ITER_MESH (f, &iter, ss->bm, BM_FACES_OF_MESH) {
+ int fset = abs(BM_ELEM_CD_GET_INT(f, ss->cd_faceset_offset));
+ if (fset > next_face_set) {
+ next_face_set = fset;
+ }
+ }
+
+ next_face_set++;
+ return next_face_set;
+ }
}
return 0;
}
@@ -727,10 +1001,12 @@ int SCULPT_face_set_next_available_get(SculptSession *ss)
#define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256
-static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter, int neighbor_index)
+static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter,
+ SculptVertRef neighbor,
+ int neighbor_index)
{
for (int i = 0; i < iter->size; i++) {
- if (iter->neighbors[i] == neighbor_index) {
+ if (iter->neighbors[i].i == neighbor.i) {
return;
}
}
@@ -739,51 +1015,61 @@ static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter, int neigh
iter->capacity += SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
if (iter->neighbors == iter->neighbors_fixed) {
- iter->neighbors = MEM_mallocN(iter->capacity * sizeof(int), "neighbor array");
+ iter->neighbors = MEM_mallocN(iter->capacity * sizeof(SculptVertRef), "neighbor array");
+ iter->neighbor_indices = MEM_mallocN(iter->capacity * sizeof(int), "neighbor array");
memcpy(iter->neighbors, iter->neighbors_fixed, sizeof(int) * iter->size);
}
else {
iter->neighbors = MEM_reallocN_id(
- iter->neighbors, iter->capacity * sizeof(int), "neighbor array");
+ iter->neighbors, iter->capacity * sizeof(SculptVertRef), "neighbor array");
+ iter->neighbor_indices = MEM_reallocN_id(
+ iter->neighbor_indices, iter->capacity * sizeof(int), "neighbor array");
}
}
- iter->neighbors[iter->size] = neighbor_index;
+ iter->neighbors[iter->size] = neighbor;
+ iter->neighbor_indices[iter->size] = neighbor_index;
iter->size++;
}
static void sculpt_vertex_neighbors_get_bmesh(SculptSession *ss,
- int index,
+ SculptVertRef index,
SculptVertexNeighborIter *iter)
{
- BMVert *v = BM_vert_at_index(ss->bm, index);
+ BMVert *v = (BMVert *)index.i;
BMIter liter;
BMLoop *l;
iter->size = 0;
iter->num_duplicates = 0;
iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
iter->neighbors = iter->neighbors_fixed;
+ iter->neighbor_indices = iter->neighbor_indices_fixed;
BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
const BMVert *adj_v[2] = {l->prev->v, l->next->v};
for (int i = 0; i < ARRAY_SIZE(adj_v); i++) {
const BMVert *v_other = adj_v[i];
- if (BM_elem_index_get(v_other) != (int)index) {
- sculpt_vertex_neighbor_add(iter, BM_elem_index_get(v_other));
+
+ if (v_other != (BMVert *)index.i) {
+ sculpt_vertex_neighbor_add(
+ iter, BKE_pbvh_make_vref((intptr_t)v_other), BM_elem_index_get(v_other));
}
}
}
}
static void sculpt_vertex_neighbors_get_faces(SculptSession *ss,
- int index,
+ SculptVertRef vertex,
SculptVertexNeighborIter *iter)
{
+ int index = BKE_pbvh_vertex_index_to_table(ss->pbvh, vertex);
+
MeshElemMap *vert_map = &ss->pmap[index];
iter->size = 0;
iter->num_duplicates = 0;
iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
iter->neighbors = iter->neighbors_fixed;
+ iter->neighbor_indices = iter->neighbor_indices_fixed;
for (int i = 0; i < ss->pmap[index].count; i++) {
const MPoly *p = &ss->mpoly[vert_map->indices[i]];
@@ -791,7 +1077,7 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss,
if (poly_get_adj_loops_from_vert(p, ss->mloop, index, f_adj_v) != -1) {
for (int j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
if (f_adj_v[j] != index) {
- sculpt_vertex_neighbor_add(iter, f_adj_v[j]);
+ sculpt_vertex_neighbor_add(iter, BKE_pbvh_make_vref(f_adj_v[j]), f_adj_v[j]);
}
}
}
@@ -799,17 +1085,21 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss,
if (ss->fake_neighbors.use_fake_neighbors) {
BLI_assert(ss->fake_neighbors.fake_neighbor_index != NULL);
- if (ss->fake_neighbors.fake_neighbor_index[index] != FAKE_NEIGHBOR_NONE) {
- sculpt_vertex_neighbor_add(iter, ss->fake_neighbors.fake_neighbor_index[index]);
+ if (ss->fake_neighbors.fake_neighbor_index[index].i != FAKE_NEIGHBOR_NONE) {
+ sculpt_vertex_neighbor_add(iter,
+ ss->fake_neighbors.fake_neighbor_index[index],
+ ss->fake_neighbors.fake_neighbor_index[index].i);
}
}
}
static void sculpt_vertex_neighbors_get_grids(SculptSession *ss,
- const int index,
+ const SculptVertRef vertex,
const bool include_duplicates,
SculptVertexNeighborIter *iter)
{
+ int index = (int)vertex.i;
+
/* TODO: optimize this. We could fill #SculptVertexNeighborIter directly,
* maybe provide coordinate and mask pointers directly rather than converting
* back and forth between #CCGElem and global index. */
@@ -828,17 +1118,21 @@ static void sculpt_vertex_neighbors_get_grids(SculptSession *ss,
iter->num_duplicates = neighbors.num_duplicates;
iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
iter->neighbors = iter->neighbors_fixed;
+ iter->neighbor_indices = iter->neighbor_indices_fixed;
for (int i = 0; i < neighbors.size; i++) {
- sculpt_vertex_neighbor_add(iter,
- neighbors.coords[i].grid_index * key->grid_area +
- neighbors.coords[i].y * key->grid_size + neighbors.coords[i].x);
+ int idx = neighbors.coords[i].grid_index * key->grid_area +
+ neighbors.coords[i].y * key->grid_size + neighbors.coords[i].x;
+
+ sculpt_vertex_neighbor_add(iter, BKE_pbvh_make_vref(idx), idx);
}
if (ss->fake_neighbors.use_fake_neighbors) {
BLI_assert(ss->fake_neighbors.fake_neighbor_index != NULL);
- if (ss->fake_neighbors.fake_neighbor_index[index] != FAKE_NEIGHBOR_NONE) {
- sculpt_vertex_neighbor_add(iter, ss->fake_neighbors.fake_neighbor_index[index]);
+ if (ss->fake_neighbors.fake_neighbor_index[index].i != FAKE_NEIGHBOR_NONE) {
+ sculpt_vertex_neighbor_add(iter,
+ ss->fake_neighbors.fake_neighbor_index[index],
+ ss->fake_neighbors.fake_neighbor_index[index].i);
}
}
@@ -848,44 +1142,47 @@ static void sculpt_vertex_neighbors_get_grids(SculptSession *ss,
}
void SCULPT_vertex_neighbors_get(SculptSession *ss,
- const int index,
+ const SculptVertRef vertex,
const bool include_duplicates,
SculptVertexNeighborIter *iter)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
- sculpt_vertex_neighbors_get_faces(ss, index, iter);
+ sculpt_vertex_neighbors_get_faces(ss, vertex, iter);
return;
case PBVH_BMESH:
- sculpt_vertex_neighbors_get_bmesh(ss, index, iter);
+ sculpt_vertex_neighbors_get_bmesh(ss, vertex, iter);
return;
case PBVH_GRIDS:
- sculpt_vertex_neighbors_get_grids(ss, index, include_duplicates, iter);
+ sculpt_vertex_neighbors_get_grids(ss, vertex, include_duplicates, iter);
return;
}
}
-static bool sculpt_check_boundary_vertex_in_base_mesh(const SculptSession *ss, const int index)
+static bool sculpt_check_boundary_vertex_in_base_mesh(const SculptSession *ss,
+ const SculptVertRef index)
{
BLI_assert(ss->vertex_info.boundary);
- return BLI_BITMAP_TEST(ss->vertex_info.boundary, index);
+ return BLI_BITMAP_TEST(ss->vertex_info.boundary,
+ BKE_pbvh_vertex_index_to_table(ss->pbvh, index));
}
-bool SCULPT_vertex_is_boundary(const SculptSession *ss, const int index)
+bool SCULPT_vertex_is_boundary(const SculptSession *ss, const SculptVertRef vertex)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
- if (!SCULPT_vertex_all_face_sets_visible_get(ss, index)) {
+ if (!SCULPT_vertex_all_face_sets_visible_get(ss, vertex)) {
return true;
}
- return sculpt_check_boundary_vertex_in_base_mesh(ss, index);
+ return sculpt_check_boundary_vertex_in_base_mesh(ss, vertex);
}
case PBVH_BMESH: {
- BMVert *v = BM_vert_at_index(ss->bm, index);
+ BMVert *v = (BMVert *)vertex.i;
return BM_vert_is_boundary(v);
}
case PBVH_GRIDS: {
+ int index = (int)vertex.i;
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
const int grid_index = index / key->grid_area;
const int vertex_index = index - grid_index * key->grid_area;
@@ -897,10 +1194,10 @@ bool SCULPT_vertex_is_boundary(const SculptSession *ss, const int index)
ss->subdiv_ccg, &coord, ss->mloop, ss->mpoly, &v1, &v2);
switch (adjacency) {
case SUBDIV_CCG_ADJACENT_VERTEX:
- return sculpt_check_boundary_vertex_in_base_mesh(ss, v1);
+ return sculpt_check_boundary_vertex_in_base_mesh(ss, BKE_pbvh_make_vref(v1));
case SUBDIV_CCG_ADJACENT_EDGE:
- return sculpt_check_boundary_vertex_in_base_mesh(ss, v1) &&
- sculpt_check_boundary_vertex_in_base_mesh(ss, v2);
+ return sculpt_check_boundary_vertex_in_base_mesh(ss, BKE_pbvh_make_vref(v1)) &&
+ sculpt_check_boundary_vertex_in_base_mesh(ss, BKE_pbvh_make_vref(v2));
case SUBDIV_CCG_ADJACENT_NONE:
return false;
}
@@ -964,6 +1261,7 @@ bool SCULPT_check_vertex_pivot_symmetry(const float vco[3], const float pco[3],
typedef struct NearestVertexTLSData {
int nearest_vertex_index;
+ SculptVertRef nearest_vertex;
float nearest_vertex_distance_squared;
} NearestVertexTLSData;
@@ -982,6 +1280,7 @@ static void do_nearest_vertex_get_task_cb(void *__restrict userdata,
if (distance_squared < nvtd->nearest_vertex_distance_squared &&
distance_squared < data->max_distance_squared) {
nvtd->nearest_vertex_index = vd.index;
+ nvtd->nearest_vertex = vd.vertex;
nvtd->nearest_vertex_distance_squared = distance_squared;
}
}
@@ -996,15 +1295,17 @@ static void nearest_vertex_get_reduce(const void *__restrict UNUSED(userdata),
NearestVertexTLSData *nvtd = chunk;
if (join->nearest_vertex_index == -1) {
join->nearest_vertex_index = nvtd->nearest_vertex_index;
+ join->nearest_vertex = nvtd->nearest_vertex;
join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared;
}
else if (nvtd->nearest_vertex_distance_squared < join->nearest_vertex_distance_squared) {
join->nearest_vertex_index = nvtd->nearest_vertex_index;
+ join->nearest_vertex = nvtd->nearest_vertex;
join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared;
}
}
-int SCULPT_nearest_vertex_get(
+SculptVertRef SCULPT_nearest_vertex_get(
Sculpt *sd, Object *ob, const float co[3], float max_distance, bool use_original)
{
SculptSession *ss = ob->sculpt;
@@ -1019,7 +1320,7 @@ int SCULPT_nearest_vertex_get(
};
BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, &totnode);
if (totnode == 0) {
- return -1;
+ return BKE_pbvh_make_vref(-1);
}
SculptThreadedTaskData task_data = {
@@ -1032,6 +1333,7 @@ int SCULPT_nearest_vertex_get(
copy_v3_v3(task_data.nearest_vertex_search_co, co);
NearestVertexTLSData nvtd;
nvtd.nearest_vertex_index = -1;
+ nvtd.nearest_vertex.i = -1;
nvtd.nearest_vertex_distance_squared = FLT_MAX;
TaskParallelSettings settings;
@@ -1043,7 +1345,7 @@ int SCULPT_nearest_vertex_get(
MEM_SAFE_FREE(nodes);
- return nvtd.nearest_vertex_index;
+ return nvtd.nearest_vertex;
}
bool SCULPT_is_symmetry_iteration_valid(char i, char symm)
@@ -1094,11 +1396,11 @@ void SCULPT_floodfill_init(SculptSession *ss, SculptFloodFill *flood)
int vertex_count = SCULPT_vertex_count_get(ss);
SCULPT_vertex_random_access_ensure(ss);
- flood->queue = BLI_gsqueue_new(sizeof(int));
+ flood->queue = BLI_gsqueue_new(sizeof(SculptVertRef));
flood->visited_vertices = BLI_BITMAP_NEW(vertex_count, "visited vertices");
}
-void SCULPT_floodfill_add_initial(SculptFloodFill *flood, int index)
+void SCULPT_floodfill_add_initial(SculptFloodFill *flood, SculptVertRef index)
{
BLI_gsqueue_push(flood->queue, &index);
}
@@ -1110,7 +1412,7 @@ void SCULPT_floodfill_add_and_skip_initial(SculptFloodFill *flood, int index)
}
void SCULPT_floodfill_add_initial_with_symmetry(
- Sculpt *sd, Object *ob, SculptSession *ss, SculptFloodFill *flood, int index, float radius)
+ Sculpt *sd, Object *ob, SculptSession *ss, SculptFloodFill *flood, SculptVertRef index, float radius)
{
/* Add active vertex and symmetric vertices to the queue. */
const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
@@ -1118,18 +1420,18 @@ void SCULPT_floodfill_add_initial_with_symmetry(
if (!SCULPT_is_symmetry_iteration_valid(i, symm)) {
continue;
}
- int v = -1;
+ SculptVertRef v = {-1};
if (i == 0) {
- v = index;
+ v = vertex;
}
else if (radius > 0.0f) {
float radius_squared = (radius == FLT_MAX) ? FLT_MAX : radius * radius;
float location[3];
- flip_v3_v3(location, SCULPT_vertex_co_get(ss, index), i);
+ flip_v3_v3(location, SCULPT_vertex_co_get(ss, vertex), i);
v = SCULPT_nearest_vertex_get(sd, ob, location, radius_squared, false);
}
- if (v != -1) {
+ if (v.i != -1) {
SCULPT_floodfill_add_initial(flood, v);
}
}
@@ -1144,7 +1446,9 @@ void SCULPT_floodfill_add_active(
if (!SCULPT_is_symmetry_iteration_valid(i, symm)) {
continue;
}
- int v = -1;
+
+ SculptVertRef v = {-1};
+
if (i == 0) {
v = SCULPT_active_vertex_get(ss);
}
@@ -1155,26 +1459,30 @@ void SCULPT_floodfill_add_active(
v = SCULPT_nearest_vertex_get(sd, ob, location, radius_squared, false);
}
- if (v != -1) {
+ if (v.i != -1) {
SCULPT_floodfill_add_initial(flood, v);
}
}
}
-void SCULPT_floodfill_execute(
- SculptSession *ss,
- SculptFloodFill *flood,
- bool (*func)(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata),
- void *userdata)
+void SCULPT_floodfill_execute(SculptSession *ss,
+ SculptFloodFill *flood,
+ bool (*func)(SculptSession *ss,
+ SculptVertRef from_v,
+ SculptVertRef to_v,
+ bool is_duplicate,
+ void *userdata),
+ void *userdata)
{
while (!BLI_gsqueue_is_empty(flood->queue)) {
- int from_v;
+ SculptVertRef from_v;
BLI_gsqueue_pop(flood->queue, &from_v);
SculptVertexNeighborIter ni;
SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) {
- const int to_v = ni.index;
+ const SculptVertRef to_v = ni.vertex;
+ const int to_index = BKE_pbvh_vertex_index_to_table(ss->pbvh, to_v);
- if (BLI_BITMAP_TEST(flood->visited_vertices, to_v)) {
+ if (BLI_BITMAP_TEST(flood->visited_vertices, to_index)) {
continue;
}
@@ -1182,7 +1490,7 @@ void SCULPT_floodfill_execute(
continue;
}
- BLI_BITMAP_ENABLE(flood->visited_vertices, to_v);
+ BLI_BITMAP_ENABLE(flood->visited_vertices, to_index);
if (func(ss, from_v, to_v, ni.is_duplicate, userdata)) {
BLI_gsqueue_push(flood->queue, &to_v);
@@ -1217,6 +1525,8 @@ static bool sculpt_tool_needs_original(const char sculpt_tool)
SCULPT_TOOL_DRAW_SHARP,
SCULPT_TOOL_ELASTIC_DEFORM,
SCULPT_TOOL_SMOOTH,
+ SCULPT_TOOL_PAINT,
+ SCULPT_TOOL_VCOL_BOUNDARY,
SCULPT_TOOL_BOUNDARY,
SCULPT_TOOL_POSE);
}
@@ -1289,10 +1599,14 @@ void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data, Object *ob, Scul
memset(data, 0, sizeof(*data));
data->unode = unode;
+ data->pbvh = ss->pbvh;
+ data->ss = ss;
+
if (bm) {
data->bm_log = ss->bm_log;
}
else {
+ data->datatype = data->unode->type;
data->coords = data->unode->co;
data->normals = data->unode->no;
data->vmasks = data->unode->mask;
@@ -1304,11 +1618,21 @@ void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data, Object *ob, Scul
* Initialize a #SculptOrigVertData for accessing original vertex data;
* handles #BMesh, #Mesh, and multi-resolution.
*/
-void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *node)
+void SCULPT_orig_vert_data_init(SculptOrigVertData *data,
+ Object *ob,
+ PBVHNode *node,
+ SculptUndoType type)
{
- SculptUndoNode *unode;
- unode = SCULPT_undo_push_node(ob, node, SCULPT_UNDO_COORDS);
+ SculptUndoNode *unode = NULL;
+ data->ss = ob->sculpt;
+
+ /*do not allocate an undo node for bmesh pbvh*/
+ if (!ob->sculpt->bm) {
+ unode = SCULPT_undo_push_node(ob, node, type);
+ }
+
SCULPT_orig_vert_data_unode_init(data, ob, unode);
+ data->datatype = type;
}
/**
@@ -1316,19 +1640,30 @@ void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *
*/
void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter *iter)
{
- if (orig_data->unode->type == SCULPT_UNDO_COORDS) {
+ if (orig_data->datatype == SCULPT_UNDO_COORDS) {
if (orig_data->bm_log) {
- BM_log_original_vert_data(orig_data->bm_log, iter->bm_vert, &orig_data->co, &orig_data->no);
+ orig_data->co = BM_ELEM_CD_GET_VOID_P(iter->bm_vert, orig_data->ss->cd_origco_offset);
+
+ float *no = BM_ELEM_CD_GET_VOID_P(iter->bm_vert, orig_data->ss->cd_origno_offset);
+ normal_float_to_short_v3(orig_data->_no, no);
+ orig_data->no = orig_data->_no;
+
+ orig_data->col = BM_ELEM_CD_GET_VOID_P(iter->bm_vert, orig_data->ss->cd_origvcol_offset);
}
else {
orig_data->co = orig_data->coords[iter->i];
orig_data->no = orig_data->normals[iter->i];
}
}
- else if (orig_data->unode->type == SCULPT_UNDO_COLOR) {
- orig_data->col = orig_data->colors[iter->i];
+ else if (orig_data->datatype == SCULPT_UNDO_COLOR) {
+ if (orig_data->bm_log) {
+ orig_data->col = BM_ELEM_CD_GET_VOID_P(iter->bm_vert, orig_data->ss->cd_origvcol_offset);
+ }
+ else {
+ orig_data->col = orig_data->colors[iter->i];
+ }
}
- else if (orig_data->unode->type == SCULPT_UNDO_MASK) {
+ else if (orig_data->datatype == SCULPT_UNDO_MASK) {
if (orig_data->bm_log) {
orig_data->mask = BM_log_original_mask(orig_data->bm_log, iter->bm_vert);
}
@@ -1482,7 +1817,7 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
unode = SCULPT_undo_push_node(data->ob, data->nodes[n], type);
}
else {
- unode = SCULPT_undo_get_node(data->nodes[n]);
+ unode = SCULPT_undo_get_node(data->nodes[n], type);
}
if (!unode) {
@@ -2065,11 +2400,16 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
if (use_original) {
if (unode->bm_entry) {
- const float *temp_co;
- const short *temp_no_s;
- BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &temp_co, &temp_no_s);
+ float *temp_co;
+ float *temp_no;
+
+ BKE_pbvh_bmesh_update_origvert(ss->pbvh, vd.bm_vert, &temp_co, &temp_no, NULL);
+ if (temp_no) {
+ normal_float_to_short_v3(no_s, temp_no);
+ }
+ // BM_log_original_vert_data(ss->bm, ss->bm_log, vd.bm_vert, &temp_co, &temp_no_s,
+ // false);
copy_v3_v3(co, temp_co);
- copy_v3_v3_short(no_s, temp_no_s);
}
else {
copy_v3_v3(co, unode->co[vd.i]);
@@ -2433,6 +2773,8 @@ static float brush_strength(const Sculpt *sd,
case SCULPT_TOOL_SMOOTH:
return flip * alpha * pressure * feather;
+ case SCULPT_TOOL_VCOL_BOUNDARY:
+ return flip * alpha * pressure * feather;
case SCULPT_TOOL_PINCH:
if (flip > 0.0f) {
@@ -2476,7 +2818,7 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
const short vno[3],
const float fno[3],
const float mask,
- const int vertex_index,
+ const SculptVertRef vertex_index,
const int thread_id)
{
StrokeCache *cache = ss->cache;
@@ -2880,10 +3222,10 @@ typedef struct {
float depth;
bool original;
- int active_vertex_index;
+ SculptVertRef active_vertex_index;
float *face_normal;
- int active_face_grid_index;
+ SculptFaceRef active_face_grid_index;
struct IsectRayPrecalc isect_precalc;
} SculptRaycastData;
@@ -2897,7 +3239,8 @@ typedef struct {
bool original;
} SculptFindNearestToRayData;
-static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
+__attribute__((optnone)) static void do_topology_rake_bmesh_task_cb_ex(
+ void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
{
@@ -2933,15 +3276,22 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
+
+ float direction2[3];
const float fade =
bstrength *
SCULPT_brush_strength_factor(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, vd.index, thread_id) *
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, vd.vertex, thread_id) *
ss->cache->pressure;
float avg[3], val[3];
- SCULPT_bmesh_four_neighbor_average(avg, direction, vd.bm_vert);
+ //SculptCurvatureData cdata;
+ //SCULPT_calc_principle_curvatures(ss, vd.vertex, &cdata);
+ //copy_v3_v3(direction2, cdata.principle[0]);
+ copy_v3_v3(direction2, direction);
+
+ SCULPT_bmesh_four_neighbor_average(avg, direction2, vd.bm_vert);
sub_v3_v3v3(val, avg, vd.co);
@@ -3008,7 +3358,7 @@ static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
}
const float fade = SCULPT_brush_strength_factor(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id);
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.vertex, thread_id);
if (bstrength > 0.0f) {
(*vd.mask) += fade * bstrength * (1.0f - *vd.mask);
@@ -3090,12 +3440,12 @@ static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
float limit_co[3];
float disp[3];
- SCULPT_vertex_limit_surface_get(ss, vd.index, limit_co);
+ SCULPT_vertex_limit_surface_get(ss, vd.vertex, limit_co);
sub_v3_v3v3(disp, limit_co, vd.co);
mul_v3_v3fl(proxy[vd.i], disp, fade);
@@ -3156,7 +3506,7 @@ static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
float current_disp[3];
@@ -3183,11 +3533,11 @@ static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata,
float weights_accum = 1.0f;
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
float vertex_disp[3];
float vertex_disp_norm[3];
float neighbor_limit_co[3];
- SCULPT_vertex_limit_surface_get(ss, ni.index, neighbor_limit_co);
+ SCULPT_vertex_limit_surface_get(ss, ni.vertex, neighbor_limit_co);
sub_v3_v3v3(vertex_disp,
ss->cache->limit_surface_co[ni.index],
ss->cache->limit_surface_co[vd.index]);
@@ -3228,7 +3578,7 @@ static void do_displacement_smear_store_prev_disp_task_cb_ex(
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
sub_v3_v3v3(ss->cache->prev_displacement[vd.index],
- SCULPT_vertex_co_get(ss, vd.index),
+ SCULPT_vertex_co_get(ss, vd.vertex),
ss->cache->limit_surface_co[vd.index]);
}
BKE_pbvh_vertex_iter_end;
@@ -3240,16 +3590,20 @@ static void do_displacement_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes
SculptSession *ss = ob->sculpt;
BKE_curvemapping_init(brush->curve);
+ SCULPT_vertex_random_access_ensure(ss);
const int totvert = SCULPT_vertex_count_get(ss);
if (!ss->cache->prev_displacement) {
ss->cache->prev_displacement = MEM_malloc_arrayN(
totvert, sizeof(float[3]), "prev displacement");
ss->cache->limit_surface_co = MEM_malloc_arrayN(totvert, sizeof(float[3]), "limit surface co");
+
for (int i = 0; i < totvert; i++) {
- SCULPT_vertex_limit_surface_get(ss, i, ss->cache->limit_surface_co[i]);
+ SculptVertRef vref = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
+ SCULPT_vertex_limit_surface_get(ss, vref, ss->cache->limit_surface_co[i]);
sub_v3_v3v3(ss->cache->prev_displacement[i],
- SCULPT_vertex_co_get(ss, i),
+ SCULPT_vertex_co_get(ss, vref),
ss->cache->limit_surface_co[i]);
}
}
@@ -3302,7 +3656,7 @@ static void do_draw_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -3359,7 +3713,7 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
SculptOrigVertData orig_data;
float(*proxy)[3];
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
@@ -3371,6 +3725,7 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
SCULPT_orig_vert_data_update(&orig_data, &vd);
+
if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
continue;
}
@@ -3382,7 +3737,7 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
orig_data.no,
NULL,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -3442,7 +3797,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata,
SculptOrigVertData orig_data;
float(*proxy)[3];
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
@@ -3454,6 +3809,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
SCULPT_orig_vert_data_update(&orig_data, &vd);
+
if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
continue;
}
@@ -3464,7 +3820,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata,
orig_data.no,
NULL,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
float current_disp[3];
float current_disp_norm[3];
@@ -3486,10 +3842,10 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata,
mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
float vertex_disp[3];
float vertex_disp_norm[3];
- sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co);
+ sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.vertex), vd.co);
normalize_v3_v3(vertex_disp_norm, vertex_disp);
if (dot_v3v3(current_disp_norm, vertex_disp_norm) > 0.0f) {
madd_v3_v3fl(final_disp, vertex_disp_norm, dot_v3v3(current_disp, vertex_disp));
@@ -3519,31 +3875,31 @@ void SCULPT_relax_vertex(SculptSession *ss,
int neighbor_count = 0;
zero_v3(smooth_pos);
zero_v3(boundary_normal);
- const bool is_boundary = SCULPT_vertex_is_boundary(ss, vd->index);
+ const bool is_boundary = SCULPT_vertex_is_boundary(ss, vd->vertex);
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->index, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->vertex, ni) {
neighbor_count++;
if (!filter_boundary_face_sets ||
- (filter_boundary_face_sets && !SCULPT_vertex_has_unique_face_set(ss, ni.index))) {
+ (filter_boundary_face_sets && !SCULPT_vertex_has_unique_face_set(ss, ni.vertex))) {
/* When the vertex to relax is boundary, use only connected boundary vertices for the average
* position. */
if (is_boundary) {
- if (!SCULPT_vertex_is_boundary(ss, ni.index)) {
+ if (!SCULPT_vertex_is_boundary(ss, ni.vertex)) {
continue;
}
- add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index));
+ add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.vertex));
avg_count++;
/* Calculate a normal for the constraint plane using the edges of the boundary. */
float to_neighbor[3];
- sub_v3_v3v3(to_neighbor, SCULPT_vertex_co_get(ss, ni.index), vd->co);
+ sub_v3_v3v3(to_neighbor, SCULPT_vertex_co_get(ss, ni.vertex), vd->co);
normalize_v3(to_neighbor);
add_v3_v3(boundary_normal, to_neighbor);
}
else {
- add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index));
+ add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.vertex));
avg_count++;
}
}
@@ -3572,7 +3928,7 @@ void SCULPT_relax_vertex(SculptSession *ss,
normalize_v3_v3(vno, boundary_normal);
}
else {
- SCULPT_vertex_normal_get(ss, vd->index, vno);
+ SCULPT_vertex_normal_get(ss, vd->vertex, vno);
}
if (is_zero_v3(vno)) {
@@ -3600,7 +3956,7 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n]);
@@ -3612,6 +3968,7 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
SCULPT_orig_vert_data_update(&orig_data, &vd);
+
if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
continue;
}
@@ -3622,7 +3979,7 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
orig_data.no,
NULL,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
SCULPT_relax_vertex(ss, &vd, fade * bstrength, false, vd.co);
@@ -3778,9 +4135,11 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
+
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
+
/* Offset vertex. */
const float fade = SCULPT_brush_strength_factor(ss,
brush,
@@ -3789,7 +4148,7 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
float val1[3];
float val2[3];
@@ -3835,7 +4194,7 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
/* We divide out the squared alpha and multiply by the squared crease
* to give us the pinch strength. */
- crease_correction = brush->crease_pinch_factor * brush->crease_pinch_factor;
+ crease_correction = brush->crease_pinch_factor * brush->crease_pinch_factor * 2.0;
brush_alpha = BKE_brush_alpha_get(scene, brush);
if (brush_alpha > 0.0f) {
crease_correction /= brush_alpha * brush_alpha;
@@ -3896,6 +4255,7 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
+
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -3906,7 +4266,7 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
float disp_center[3];
float x_disp[3];
@@ -3998,7 +4358,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata,
float(*proxy)[3];
const float bstrength = ss->cache->bstrength;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
@@ -4023,7 +4383,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata,
orig_data.no,
NULL,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
if (grab_silhouette) {
@@ -4087,7 +4447,7 @@ static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata,
const float bstrength = ss->cache->bstrength;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
@@ -4144,7 +4504,7 @@ static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata,
mul_v3_fl(final_disp, 1.0f - *vd.mask);
}
- mul_v3_fl(final_disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index));
+ mul_v3_fl(final_disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex));
copy_v3_v3(proxy[vd.i], final_disp);
@@ -4176,6 +4536,9 @@ static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in
};
TaskParallelSettings settings;
+
+ SCULPT_vertex_random_access_ensure(ss);
+
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings);
}
@@ -4354,7 +4717,7 @@ static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@@ -4440,7 +4803,7 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
}
@@ -4488,7 +4851,7 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
if (vd.mask) {
mul_v3_fl(disp, 1.0f - *vd.mask);
}
- mul_v3_fl(disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index));
+ mul_v3_fl(disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex));
copy_v3_v3(proxy[vd.i], disp);
}
@@ -4551,7 +4914,7 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
float(*proxy)[3];
const float bstrength = ss->cache->bstrength;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
@@ -4574,7 +4937,7 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
orig_data.no,
NULL,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@@ -4625,7 +4988,7 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
float(*proxy)[3];
const float bstrength = ss->cache->bstrength;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
@@ -4649,7 +5012,7 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
orig_data.no,
NULL,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
sub_v3_v3v3(vec, orig_data.co, ss->cache->location);
@@ -4700,13 +5063,19 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
const float bstrength = ss->cache->bstrength;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
+ bool bmeshpbvh = BKE_pbvh_type(ss->pbvh) == PBVH_BMESH;
+ if (bmeshpbvh) {
+ BM_mesh_elem_index_ensure(ss->bm, BM_VERT);
+ // BM_mesh_elem_table_ensure(ss->bm, BM_VERT);
+ }
+
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
SCULPT_orig_vert_data_update(&orig_data, &vd);
@@ -4721,7 +5090,7 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
const int vi = vd.index;
@@ -4757,9 +5126,10 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
float normal[3];
if (use_persistent_base) {
- SCULPT_vertex_persistent_normal_get(ss, vi, normal);
+ SCULPT_vertex_persistent_normal_get(ss, vd.vertex, normal);
mul_v3_fl(normal, brush->height);
- madd_v3_v3v3fl(final_co, SCULPT_vertex_persistent_co_get(ss, vi), normal, *disp_factor);
+ madd_v3_v3v3fl(
+ final_co, SCULPT_vertex_persistent_co_get(ss, vd.vertex), normal, *disp_factor);
}
else {
normal_short_to_float_v3(normal, orig_data.no);
@@ -4834,7 +5204,7 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
float val[3];
@@ -4948,9 +5318,8 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
-
mul_v3_v3fl(proxy[vd.i], val, fade);
if (vd.mvert) {
@@ -5105,7 +5474,7 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -5232,9 +5601,8 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
-
mul_v3_v3fl(proxy[vd.i], val, fade);
if (vd.mvert) {
@@ -5386,7 +5754,7 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -5485,7 +5853,7 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -5602,7 +5970,7 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -5742,7 +6110,7 @@ static void do_gravity_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -5824,6 +6192,17 @@ void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3])
BKE_keyblock_update_from_vertcos(ob, kb, vertCos);
}
+static void topology_undopush_cb(PBVHNode *node, void *data)
+{
+ SculptSearchSphereData *sdata = (SculptSearchSphereData *)data;
+
+ SCULPT_undo_push_node(sdata->ob,
+ node,
+ sdata->brush->sculpt_tool == SCULPT_TOOL_MASK ? SCULPT_UNDO_MASK :
+ SCULPT_UNDO_COORDS);
+ BKE_pbvh_node_mark_update(node);
+}
+
/* Note: we do the topology update before any brush actions to avoid
* issues with the proxies. The size of the proxy can't change, so
* topology must be updated first. */
@@ -5839,13 +6218,6 @@ static void sculpt_topology_update(Sculpt *sd,
const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true :
ss->cache->original;
const float radius_scale = 1.25f;
- PBVHNode **nodes = sculpt_pbvh_gather_generic(
- ob, sd, brush, use_original, radius_scale, &totnode);
-
- /* Only act if some verts are inside the brush area. */
- if (totnode == 0) {
- return;
- }
/* Free index based vertex info as it will become invalid after modifying the topology during the
* stroke. */
@@ -5865,30 +6237,35 @@ static void sculpt_topology_update(Sculpt *sd,
}
}
- for (n = 0; n < totnode; n++) {
- SCULPT_undo_push_node(ob,
- nodes[n],
- brush->sculpt_tool == SCULPT_TOOL_MASK ? SCULPT_UNDO_MASK :
- SCULPT_UNDO_COORDS);
- BKE_pbvh_node_mark_update(nodes[n]);
-
- if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
- BKE_pbvh_node_mark_topology_update(nodes[n]);
- BKE_pbvh_bmesh_node_save_orig(ss->bm, nodes[n]);
- }
- }
-
- if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
- BKE_pbvh_bmesh_update_topology(ss->pbvh,
- mode,
- ss->cache->location,
- ss->cache->view_normal,
- ss->cache->radius,
- (brush->flag & BRUSH_FRONTFACE) != 0,
- (brush->falloff_shape != PAINT_FALLOFF_SHAPE_SPHERE));
- }
-
- MEM_SAFE_FREE(nodes);
+ PBVHNode **nodes = NULL;
+ SculptSearchSphereData sdata = {.ss = ss,
+ .sd = sd,
+ .ob = ob,
+ .radius_squared = square_f(ss->cache->radius * radius_scale),
+ .original = use_original,
+ .ignore_fully_ineffective = brush->sculpt_tool !=
+ SCULPT_TOOL_MASK,
+ .center = NULL,
+ .brush = brush};
+
+ int symidx = ss->cache->mirror_symmetry_pass + (ss->cache->radial_symmetry_pass * 8);
+ if (symidx > 127) {
+ symidx = 127;
+ }
+
+ /* do nodes under the brush cursor */
+ BKE_pbvh_bmesh_update_topology_nodes(ss->pbvh,
+ SCULPT_search_sphere_cb,
+ topology_undopush_cb,
+ &sdata,
+ mode,
+ ss->cache->location,
+ ss->cache->view_normal,
+ ss->cache->radius,
+ (brush->flag & BRUSH_FRONTFACE) != 0,
+ (brush->falloff_shape != PAINT_FALLOFF_SHAPE_SPHERE),
+ symidx,
+ brush->sculpt_tool != SCULPT_TOOL_DRAW_SHARP);
/* Update average stroke position. */
copy_v3_v3(location, ss->cache->true_location);
@@ -5916,11 +6293,20 @@ static void do_brush_action_task_cb(void *__restrict userdata,
BKE_pbvh_node_mark_update_mask(data->nodes[n]);
}
else if (ELEM(data->brush->sculpt_tool, SCULPT_TOOL_PAINT, SCULPT_TOOL_SMEAR)) {
- SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COLOR);
+ if (!ss->bm) {
+ if (data->brush->vcol_boundary_factor > 0.0f) {
+ SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
+ }
+
+ SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COLOR);
+ }
+
BKE_pbvh_node_mark_update_color(data->nodes[n]);
}
else {
- SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
+ if (!ss->bm) {
+ SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
+ }
BKE_pbvh_node_mark_update(data->nodes[n]);
}
}
@@ -5933,11 +6319,8 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
/* Check for unsupported features. */
PBVHType type = BKE_pbvh_type(ss->pbvh);
- if (brush->sculpt_tool == SCULPT_TOOL_PAINT && type != PBVH_FACES) {
- return;
- }
-
- if (brush->sculpt_tool == SCULPT_TOOL_SMEAR && type != PBVH_FACES) {
+ if (ELEM(brush->sculpt_tool, SCULPT_TOOL_PAINT, SCULPT_TOOL_SMEAR) &&
+ !ELEM(type, PBVH_BMESH, PBVH_FACES)) {
return;
}
@@ -5969,9 +6352,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
if (brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS &&
SCULPT_stroke_is_first_brush_step(ss->cache) && !ss->cache->alt_smooth) {
- /* Dynamic-topology does not support Face Sets data, so it can't store/restore it from undo. */
- /* TODO(pablodp606): This check should be done in the undo code and not here, but the rest of
- * the sculpt code is not checking for unsupported undo types that may return a null node. */
+ // faceset undo node is created below for pbvh_bmesh
if (BKE_pbvh_type(ss->pbvh) != PBVH_BMESH) {
SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_FACE_SETS);
}
@@ -6003,16 +6384,55 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
}
float location[3];
- SculptThreadedTaskData task_data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
+ // dyntopo can't push undo nodes inside a thread
+ if (ss->bm) {
+ if (ELEM(brush->sculpt_tool, SCULPT_TOOL_PAINT, SCULPT_TOOL_SMEAR)) {
+ for (int i = 0; i < totnode; i++) {
+ int other = brush->vcol_boundary_factor > 0.0f ? SCULPT_UNDO_COORDS : -1;
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings);
+ if (SCULPT_ensure_dyntopo_node_undo(ob, nodes[i], SCULPT_UNDO_COLOR, other)) {
+ BKE_pbvh_update_origcolor_bmesh(ss->pbvh, nodes[i]);
+
+ if (other != -1) {
+ BKE_pbvh_update_origco_bmesh(ss->pbvh, nodes[i]);
+ }
+ }
+
+ BKE_pbvh_node_mark_update_color(nodes[i]);
+ // SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_COLOR);
+ }
+ }
+ else if (brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS) {
+ for (int i = 0; i < totnode; i++) {
+ if (ss->cache->alt_smooth) {
+ SCULPT_ensure_dyntopo_node_undo(ob, nodes[i], SCULPT_UNDO_FACE_SETS, SCULPT_UNDO_COORDS);
+ }
+ else {
+ SCULPT_ensure_dyntopo_node_undo(ob, nodes[i], SCULPT_UNDO_FACE_SETS, -1);
+ }
+
+ BKE_pbvh_node_mark_update(nodes[i]);
+ }
+ }
+ else {
+ for (int i = 0; i < totnode; i++) {
+ SCULPT_ensure_dyntopo_node_undo(ob, nodes[i], SCULPT_UNDO_COORDS, -1);
+ BKE_pbvh_node_mark_update(nodes[i]);
+ }
+ }
+ }
+ else {
+ SculptThreadedTaskData task_data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings);
+ }
if (sculpt_brush_needs_normal(ss, brush)) {
update_sculpt_normal(sd, ob, nodes, totnode);
@@ -6149,6 +6569,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
case SCULPT_TOOL_SMEAR:
SCULPT_do_smear_brush(sd, ob, nodes, totnode);
break;
+ case SCULPT_TOOL_VCOL_BOUNDARY:
+ SCULPT_smooth_vcol_boundary(sd, ob, nodes, totnode, ss->cache->bstrength);
+ break;
}
if (!ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_MASK) &&
@@ -6248,7 +6671,9 @@ static void sculpt_combine_proxies_task_cb(void *__restrict userdata,
if (use_orco) {
if (ss->bm) {
- copy_v3_v3(val, BM_log_original_vert_co(ss->bm_log, vd.bm_vert));
+ float *co = BM_ELEM_CD_GET_VOID_P(vd.bm_vert, ss->cd_origco_offset);
+ copy_v3_v3(val, co);
+ // copy_v3_v3(val, BM_log_original_vert_co(ss->bm_log, vd.bm_vert));
}
else {
copy_v3_v3(val, orco[vd.i]);
@@ -6338,6 +6763,10 @@ static void SCULPT_flush_stroke_deform_task_cb(void *__restrict userdata,
PBVHVertexIter vd;
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ BM_mesh_elem_index_ensure(ss->bm, BM_VERT);
+ }
+
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
sculpt_flush_pbvhvert_deform(ob, &vd);
@@ -6625,6 +7054,24 @@ bool SCULPT_vertex_colors_poll(bContext *C)
if (!U.experimental.use_sculpt_vertex_colors) {
return false;
}
+
+ Object *ob = CTX_data_active_object(C);
+
+ return SCULPT_mode_poll(C);
+}
+
+bool SCULPT_vertex_colors_poll_no_bmesh(bContext *C)
+{
+ if (!U.experimental.use_sculpt_vertex_colors) {
+ return false;
+ }
+
+ Object *ob = CTX_data_active_object(C);
+
+ if (ob && ob->sculpt && ob->sculpt->bm) {
+ return false;
+ }
+
return SCULPT_mode_poll(C);
}
@@ -6712,6 +7159,8 @@ static const char *sculpt_tool_name(Sculpt *sd)
return "Paint Brush";
case SCULPT_TOOL_SMEAR:
return "Smear Brush";
+ case SCULPT_TOOL_VCOL_BOUNDARY:
+ return "Color Boundary";
}
return "Sculpting";
@@ -7324,6 +7773,8 @@ static bool sculpt_needs_connectivity_info(const Sculpt *sd,
(brush->sculpt_tool == SCULPT_TOOL_SMOOTH) || (brush->autosmooth_factor > 0) ||
((brush->sculpt_tool == SCULPT_TOOL_MASK) && (brush->mask_tool == BRUSH_MASK_SMOOTH)) ||
(brush->sculpt_tool == SCULPT_TOOL_POSE) ||
+ (brush->sculpt_tool == SCULPT_TOOL_VCOL_BOUNDARY) ||
+ (brush->sculpt_tool == SCULPT_TOOL_PAINT && brush->vcol_boundary_factor > 0.0f) ||
(brush->sculpt_tool == SCULPT_TOOL_BOUNDARY) ||
(brush->sculpt_tool == SCULPT_TOOL_SLIDE_RELAX) ||
(brush->sculpt_tool == SCULPT_TOOL_CLOTH) || (brush->sculpt_tool == SCULPT_TOOL_SMEAR) ||
@@ -7360,7 +7811,7 @@ static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin)
}
else {
/* Intersect with coordinates from before we started stroke. */
- SculptUndoNode *unode = SCULPT_undo_get_node(node);
+ SculptUndoNode *unode = SCULPT_undo_get_node(node, SCULPT_UNDO_COORDS);
origco = (unode) ? unode->co : NULL;
use_origco = origco ? true : false;
}
@@ -7397,7 +7848,7 @@ static void sculpt_find_nearest_to_ray_cb(PBVHNode *node, void *data_v, float *t
}
else {
/* Intersect with coordinates from before we started stroke. */
- SculptUndoNode *unode = SCULPT_undo_get_node(node);
+ SculptUndoNode *unode = SCULPT_undo_get_node(node, SCULPT_UNDO_COORDS);
origco = (unode) ? unode->co : NULL;
use_origco = origco ? true : false;
}
@@ -7512,7 +7963,10 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
/* Update the active vertex of the SculptSession. */
ss->active_vertex_index = srd.active_vertex_index;
- SCULPT_vertex_random_access_ensure(ss);
+
+ if (BKE_pbvh_type(ss->pbvh) != PBVH_BMESH) {
+ SCULPT_vertex_random_access_ensure(ss);
+ }
copy_v3_v3(out->active_vertex_co, SCULPT_active_vertex_co_get(ss));
switch (BKE_pbvh_type(ss->pbvh)) {
@@ -7521,11 +7975,11 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
ss->active_grid_index = 0;
break;
case PBVH_GRIDS:
- ss->active_face_index = 0;
- ss->active_grid_index = srd.active_face_grid_index;
+ ss->active_face_index.i = 0;
+ ss->active_grid_index = srd.active_face_grid_index.i;
break;
case PBVH_BMESH:
- ss->active_face_index = 0;
+ ss->active_face_index = srd.active_face_grid_index;
ss->active_grid_index = 0;
break;
}
@@ -7612,11 +8066,6 @@ bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mouse[2])
depth = SCULPT_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original);
- if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
- BM_mesh_elem_table_ensure(ss->bm, BM_VERT);
- BM_mesh_elem_index_ensure(ss->bm, BM_VERT);
- }
-
bool hit = false;
{
SculptRaycastData srd;
@@ -7823,6 +8272,13 @@ void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags)
}
}
+bool all_nodes_callback(PBVHNode *node, void *data)
+{
+ return true;
+}
+
+void sculpt_undo_print_nodes(void *active);
+
void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType update_flags)
{
/* After we are done drawing the stroke, check if we need to do a more
@@ -7874,12 +8330,31 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up
BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask);
}
- if (update_flags & SCULPT_UPDATE_COLOR) {
- BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateColor);
- }
-
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
BKE_pbvh_bmesh_after_stroke(ss->pbvh);
+#if 0
+ if (update_flags & SCULPT_UPDATE_COLOR) {
+ PBVHNode **nodes;
+ int totnode = 0;
+
+ // BKE_pbvh_get_nodes(ss->pbvh, PBVH_UpdateColor, &nodes, &totnode);
+ BKE_pbvh_search_gather(ss->pbvh, all_nodes_callback, NULL, &nodes, &totnode);
+
+ for (int i = 0; i < totnode; i++) {
+ SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_COLOR);
+ }
+
+ if (nodes) {
+ MEM_freeN(nodes);
+ }
+ }
+#endif
+
+ sculpt_undo_print_nodes(NULL);
+ }
+
+ if (update_flags & SCULPT_UPDATE_COLOR) {
+ BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateColor);
}
/* Optimization: if there is locked key and active modifiers present in */
@@ -8201,8 +8676,10 @@ static int sculpt_set_persistent_base_exec(bContext *C, wmOperator *UNUSED(op))
"layer persistent base");
for (int i = 0; i < totvert; i++) {
- copy_v3_v3(ss->persistent_base[i].co, SCULPT_vertex_co_get(ss, i));
- SCULPT_vertex_normal_get(ss, i, ss->persistent_base[i].no);
+ SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
+ copy_v3_v3(ss->persistent_base[i].co, SCULPT_vertex_co_get(ss, vertex));
+ SCULPT_vertex_normal_get(ss, vertex, ss->persistent_base[i].no);
ss->persistent_base[i].disp = 0.0f;
}
@@ -8264,6 +8741,22 @@ static bool sculpt_no_multires_poll(bContext *C)
return false;
}
+/* checks if pbvh needs to sync its flat vcol shading flag with scene tool settings
+ scene and ob are allowd to be NULL (in which case nothing is done).
+*/
+void SCULPT_update_flat_vcol_shading(Object *ob, Scene *scene)
+{
+ if (!scene || !ob || !ob->sculpt || !ob->sculpt->pbvh) {
+ return;
+ }
+
+ if (ob->sculpt->pbvh) {
+ bool flat_vcol_shading = ((scene->toolsettings->sculpt->flags &
+ SCULPT_DYNTOPO_FLAT_VCOL_SHADING) != 0);
+
+ BKE_pbvh_set_flat_vcol_shading(ob->sculpt->pbvh, flat_vcol_shading);
+ }
+}
static int sculpt_symmetrize_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -8645,29 +9138,38 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float
const int max_preview_vertices = SCULPT_vertex_count_get(ss) * 3 * 2;
if (ss->preview_vert_index_list == NULL) {
- ss->preview_vert_index_list = MEM_callocN(max_preview_vertices * sizeof(int), "preview lines");
+ ss->preview_vert_index_list = MEM_callocN(max_preview_vertices * sizeof(SculptVertRef),
+ "preview lines");
}
- GSQueue *not_visited_vertices = BLI_gsqueue_new(sizeof(int));
- int active_v = SCULPT_active_vertex_get(ss);
+ GSQueue *not_visited_vertices = BLI_gsqueue_new(sizeof(SculptVertRef));
+ SculptVertRef active_v = SCULPT_active_vertex_get(ss);
BLI_gsqueue_push(not_visited_vertices, &active_v);
while (!BLI_gsqueue_is_empty(not_visited_vertices)) {
- int from_v;
+ SculptVertRef from_v;
+
BLI_gsqueue_pop(not_visited_vertices, &from_v);
+
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) {
if (totpoints + (ni.size * 2) < max_preview_vertices) {
- int to_v = ni.index;
+ SculptVertRef to_v = ni.vertex;
+ int to_v_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, to_v);
+
ss->preview_vert_index_list[totpoints] = from_v;
totpoints++;
ss->preview_vert_index_list[totpoints] = to_v;
totpoints++;
- if (BLI_BITMAP_TEST(visited_vertices, to_v)) {
+
+ if (BLI_BITMAP_TEST(visited_vertices, to_v_i)) {
continue;
}
- BLI_BITMAP_ENABLE(visited_vertices, to_v);
+
+ BLI_BITMAP_ENABLE(visited_vertices, to_v_i);
+
const float *co = SCULPT_vertex_co_for_grab_active_get(ss, to_v);
+
if (len_squared_v3v3(brush_co, co) < radius * radius) {
BLI_gsqueue_push(not_visited_vertices, &to_v);
}
@@ -8740,7 +9242,7 @@ static void SCULPT_OT_vertex_to_loop_colors(wmOperatorType *ot)
ot->idname = "SCULPT_OT_vertex_to_loop_colors";
/* api callbacks */
- ot->poll = SCULPT_vertex_colors_poll;
+ ot->poll = SCULPT_vertex_colors_poll_no_bmesh;
ot->exec = vertex_to_loop_colors_exec;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -8803,7 +9305,7 @@ static void SCULPT_OT_loop_to_vertex_colors(wmOperatorType *ot)
ot->idname = "SCULPT_OT_loop_to_vertex_colors";
/* api callbacks */
- ot->poll = SCULPT_vertex_colors_poll;
+ ot->poll = SCULPT_vertex_colors_poll_no_bmesh;
ot->exec = loop_to_vertex_colors_exec;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -8818,7 +9320,7 @@ static int sculpt_sample_color_invoke(bContext *C,
Object *ob = CTX_data_active_object(C);
Brush *brush = BKE_paint_brush(&sd->paint);
SculptSession *ss = ob->sculpt;
- int active_vertex = SCULPT_active_vertex_get(ss);
+ SculptVertRef active_vertex = SCULPT_active_vertex_get(ss);
const float *active_vertex_color = SCULPT_vertex_color_get(ss, active_vertex);
if (!active_vertex_color) {
return OPERATOR_CANCELLED;
@@ -8875,10 +9377,14 @@ enum {
SCULPT_TOPOLOGY_ID_DEFAULT,
};
-static int SCULPT_vertex_get_connected_component(SculptSession *ss, int index)
+static int SCULPT_vertex_get_connected_component(SculptSession *ss, SculptVertRef vertex)
{
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ vertex.i = BM_elem_index_get((BMVert *)vertex.i);
+ }
+
if (ss->vertex_info.connected_component) {
- return ss->vertex_info.connected_component[index];
+ return ss->vertex_info.connected_component[vertex.i];
}
return SCULPT_TOPOLOGY_ID_DEFAULT;
}
@@ -8887,19 +9393,28 @@ static void SCULPT_fake_neighbor_init(SculptSession *ss, const float max_dist)
{
const int totvert = SCULPT_vertex_count_get(ss);
ss->fake_neighbors.fake_neighbor_index = MEM_malloc_arrayN(
- totvert, sizeof(int), "fake neighbor");
+ totvert, sizeof(SculptVertRef), "fake neighbor");
for (int i = 0; i < totvert; i++) {
- ss->fake_neighbors.fake_neighbor_index[i] = FAKE_NEIGHBOR_NONE;
+ ss->fake_neighbors.fake_neighbor_index[i].i = FAKE_NEIGHBOR_NONE;
}
ss->fake_neighbors.current_max_distance = max_dist;
}
-static void SCULPT_fake_neighbor_add(SculptSession *ss, int v_index_a, int v_index_b)
+static void SCULPT_fake_neighbor_add(SculptSession *ss,
+ SculptVertRef v_index_a,
+ SculptVertRef v_index_b)
{
- if (ss->fake_neighbors.fake_neighbor_index[v_index_a] == FAKE_NEIGHBOR_NONE) {
- ss->fake_neighbors.fake_neighbor_index[v_index_a] = v_index_b;
- ss->fake_neighbors.fake_neighbor_index[v_index_b] = v_index_a;
+ int tablea = (int)v_index_a.i, tableb = (int)v_index_b.i;
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ tablea = BM_elem_index_get((BMVert *)v_index_a.i);
+ tableb = BM_elem_index_get((BMVert *)v_index_b.i);
+ }
+
+ if (ss->fake_neighbors.fake_neighbor_index[tablea].i == FAKE_NEIGHBOR_NONE) {
+ ss->fake_neighbors.fake_neighbor_index[tablea] = v_index_b;
+ ss->fake_neighbors.fake_neighbor_index[tableb] = v_index_a;
}
}
@@ -8910,6 +9425,7 @@ static void sculpt_pose_fake_neighbors_free(SculptSession *ss)
typedef struct NearestVertexFakeNeighborTLSData {
int nearest_vertex_index;
+ SculptVertRef nearest_vertex;
float nearest_vertex_distance_squared;
int current_topology_id;
} NearestVertexFakeNeighborTLSData;
@@ -8923,15 +9439,20 @@ static void do_fake_neighbor_search_task_cb(void *__restrict userdata,
NearestVertexFakeNeighborTLSData *nvtd = tls->userdata_chunk;
PBVHVertexIter vd;
+ bool has_bmesh = false;
+
+ SCULPT_vertex_random_access_ensure(ss);
+
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- int vd_topology_id = SCULPT_vertex_get_connected_component(ss, vd.index);
+ int vd_topology_id = SCULPT_vertex_get_connected_component(ss, vd.vertex);
if (vd_topology_id != nvtd->current_topology_id &&
- ss->fake_neighbors.fake_neighbor_index[vd.index] == FAKE_NEIGHBOR_NONE) {
+ ss->fake_neighbors.fake_neighbor_index[vd.index].i == FAKE_NEIGHBOR_NONE) {
float distance_squared = len_squared_v3v3(vd.co, data->nearest_vertex_search_co);
if (distance_squared < nvtd->nearest_vertex_distance_squared &&
distance_squared < data->max_distance_squared) {
nvtd->nearest_vertex_index = vd.index;
+ nvtd->nearest_vertex = vd.vertex;
nvtd->nearest_vertex_distance_squared = distance_squared;
}
}
@@ -8945,17 +9466,23 @@ static void fake_neighbor_search_reduce(const void *__restrict UNUSED(userdata),
{
NearestVertexFakeNeighborTLSData *join = chunk_join;
NearestVertexFakeNeighborTLSData *nvtd = chunk;
+
if (join->nearest_vertex_index == -1) {
join->nearest_vertex_index = nvtd->nearest_vertex_index;
+ join->nearest_vertex = nvtd->nearest_vertex;
join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared;
}
else if (nvtd->nearest_vertex_distance_squared < join->nearest_vertex_distance_squared) {
join->nearest_vertex_index = nvtd->nearest_vertex_index;
+ join->nearest_vertex = nvtd->nearest_vertex;
join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared;
}
}
-static int SCULPT_fake_neighbor_search(Sculpt *sd, Object *ob, const int index, float max_distance)
+static SculptVertRef SCULPT_fake_neighbor_search(Sculpt *sd,
+ Object *ob,
+ const SculptVertRef index,
+ float max_distance)
{
SculptSession *ss = ob->sculpt;
PBVHNode **nodes = NULL;
@@ -8970,7 +9497,7 @@ static int SCULPT_fake_neighbor_search(Sculpt *sd, Object *ob, const int index,
BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, &totnode);
if (totnode == 0) {
- return -1;
+ return BKE_pbvh_make_vref(-1);
}
SculptThreadedTaskData task_data = {
@@ -8984,6 +9511,7 @@ static int SCULPT_fake_neighbor_search(Sculpt *sd, Object *ob, const int index,
NearestVertexFakeNeighborTLSData nvtd;
nvtd.nearest_vertex_index = -1;
+ nvtd.nearest_vertex.i = -1;
nvtd.nearest_vertex_distance_squared = FLT_MAX;
nvtd.current_topology_id = SCULPT_vertex_get_connected_component(ss, index);
@@ -8996,19 +9524,24 @@ static int SCULPT_fake_neighbor_search(Sculpt *sd, Object *ob, const int index,
MEM_SAFE_FREE(nodes);
- return nvtd.nearest_vertex_index;
+ return nvtd.nearest_vertex;
}
typedef struct SculptTopologyIDFloodFillData {
int next_id;
} SculptTopologyIDFloodFillData;
-static bool SCULPT_connected_components_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool UNUSED(is_duplicate), void *userdata)
+static bool SCULPT_connected_components_floodfill_cb(SculptSession *ss,
+ SculptVertRef from_v,
+ SculptVertRef to_v,
+ bool UNUSED(is_duplicate),
+ void *userdata)
{
SculptTopologyIDFloodFillData *data = userdata;
- ss->vertex_info.connected_component[from_v] = data->next_id;
- ss->vertex_info.connected_component[to_v] = data->next_id;
+ ss->vertex_info.connected_component[BKE_pbvh_vertex_index_to_table(ss->pbvh, from_v)] =
+ data->next_id;
+ ss->vertex_info.connected_component[BKE_pbvh_vertex_index_to_table(ss->pbvh, to_v)] =
+ data->next_id;
return true;
}
@@ -9016,6 +9549,8 @@ void SCULPT_connected_components_ensure(Object *ob)
{
SculptSession *ss = ob->sculpt;
+ SCULPT_vertex_random_access_ensure(ss);
+
/* Topology IDs already initialized. They only need to be recalculated when the PBVH is rebuild.
*/
if (ss->vertex_info.connected_component) {
@@ -9031,10 +9566,12 @@ void SCULPT_connected_components_ensure(Object *ob)
int next_id = 0;
for (int i = 0; i < totvert; i++) {
+ SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
if (ss->vertex_info.connected_component[i] == SCULPT_TOPOLOGY_ID_NONE) {
SculptFloodFill flood;
SCULPT_floodfill_init(ss, &flood);
- SCULPT_floodfill_add_initial(&flood, i);
+ SCULPT_floodfill_add_initial(&flood, vertex);
SculptTopologyIDFloodFillData data;
data.next_id = next_id;
SCULPT_floodfill_execute(ss, &flood, SCULPT_connected_components_floodfill_cb, &data);
@@ -9091,12 +9628,13 @@ void SCULPT_fake_neighbors_ensure(Sculpt *sd, Object *ob, const float max_dist)
SCULPT_fake_neighbor_init(ss, max_dist);
for (int i = 0; i < totvert; i++) {
- const int from_v = i;
+ const SculptVertRef from_v = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
+ /* This vertex does not have a fake neighbor yet, seach one for it. */
+ if (ss->fake_neighbors.fake_neighbor_index[i].i == FAKE_NEIGHBOR_NONE) {
+ const SculptVertRef to_v = SCULPT_fake_neighbor_search(sd, ob, from_v, max_dist);
- /* This vertex does not have a fake neighbor yet, search one for it. */
- if (ss->fake_neighbors.fake_neighbor_index[from_v] == FAKE_NEIGHBOR_NONE) {
- const int to_v = SCULPT_fake_neighbor_search(sd, ob, from_v, max_dist);
- if (to_v != -1) {
+ if (to_v.i != -1) {
/* Add the fake neighbor if available. */
SCULPT_fake_neighbor_add(ss, from_v, to_v);
}
@@ -9214,16 +9752,19 @@ static void do_mask_by_color_contiguous_update_nodes_cb(
}
static bool sculpt_mask_by_color_contiguous_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+ SculptSession *ss, SculptVertRef from_v, SculptVertRef to_v, bool is_duplicate, void *userdata)
{
MaskByColorContiguousFloodFillData *data = userdata;
+ int to_v_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, to_v);
+ int from_v_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, from_v);
+
const float *current_color = SCULPT_vertex_color_get(ss, to_v);
float new_vertex_mask = sculpt_mask_by_color_delta_get(
current_color, data->initial_color, data->threshold, data->invert);
- data->new_mask[to_v] = new_vertex_mask;
+ data->new_mask[to_v_i] = new_vertex_mask;
if (is_duplicate) {
- data->new_mask[to_v] = data->new_mask[from_v];
+ data->new_mask[to_v_i] = data->new_mask[from_v_i];
}
float len = len_v3v3(current_color, data->initial_color);
@@ -9232,7 +9773,7 @@ static bool sculpt_mask_by_color_contiguous_floodfill_cb(
}
static void sculpt_mask_by_color_contiguous(Object *object,
- const int vertex,
+ const SculptVertRef vertex,
const float threshold,
const bool invert,
const bool preserve_mask)
@@ -9322,7 +9863,7 @@ static void do_mask_by_color_task_cb(void *__restrict userdata,
}
static void sculpt_mask_by_color_full_mesh(Object *object,
- const int vertex,
+ const SculptVertRef vertex,
const float threshold,
const bool invert,
const bool preserve_mask)
@@ -9378,7 +9919,7 @@ static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEven
SCULPT_undo_push_begin(ob, "Mask by color");
- const int active_vertex = SCULPT_active_vertex_get(ss);
+ const SculptVertRef active_vertex = SCULPT_active_vertex_get(ss);
const float threshold = RNA_float_get(op->ptr, "threshold");
const bool invert = RNA_boolean_get(op->ptr, "invert");
const bool preserve_mask = RNA_boolean_get(op->ptr, "preserve_previous_mask");
@@ -9573,14 +10114,14 @@ static void dyntopo_detail_size_sample_from_surface(Object *ob,
DyntopoDetailSizeEditCustomData *cd)
{
SculptSession *ss = ob->sculpt;
- const int active_vertex = SCULPT_active_vertex_get(ss);
+ const SculptVertRef active_vertex = SCULPT_active_vertex_get(ss);
float len_accum = 0;
int num_neighbors = 0;
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, active_vertex, ni) {
len_accum += len_v3v3(SCULPT_vertex_co_get(ss, active_vertex),
- SCULPT_vertex_co_get(ss, ni.index));
+ SCULPT_vertex_co_get(ss, ni.vertex));
num_neighbors++;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.c b/source/blender/editors/sculpt_paint/sculpt_automasking.c
index 5f5fb51d75f..6427d6eeb4f 100644
--- a/source/blender/editors/sculpt_paint/sculpt_automasking.c
+++ b/source/blender/editors/sculpt_paint/sculpt_automasking.c
@@ -100,6 +100,13 @@ bool SCULPT_is_automasking_enabled(const Sculpt *sd, const SculptSession *ss, co
if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS)) {
return true;
}
+ if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_CONCAVITY)) {
+ return true;
+ }
+ if (br->concave_mask_factor > 0.0f) {
+ return true;
+ }
+
return false;
}
@@ -127,16 +134,42 @@ static bool SCULPT_automasking_needs_factors_cache(const Sculpt *sd, const Brush
return false;
}
-float SCULPT_automasking_factor_get(AutomaskingCache *automasking, SculptSession *ss, int vert)
+float SCULPT_automasking_factor_get(AutomaskingCache *automasking,
+ SculptSession *ss,
+ SculptVertRef vert)
{
+ float mask = 1.0f;
+ bool do_concave;
+
if (!automasking) {
- return 1.0f;
+ return mask;
}
+
+ do_concave = ss->cache->brush->concave_mask_factor > 0.0f ||
+ (automasking->settings.flags & BRUSH_AUTOMASKING_CONCAVITY);
+
/* If the cache is initialized with valid info, use the cache. This is used when the
* automasking information can't be computed in real time per vertex and needs to be
* initialized for the whole mesh when the stroke starts. */
if (automasking->factor) {
- return automasking->factor[vert];
+ mask = automasking->factor[BKE_pbvh_vertex_index_to_table(ss->pbvh, vert)];
+ }
+
+ if (do_concave) {
+ if (!automasking->factor) {
+ mask = SCULPT_calc_concavity(ss, vert);
+ }
+
+ if (automasking->settings.flags & BRUSH_AUTOMASKING_INVERT_CONCAVITY) {
+ mask = 1.0 - mask;
+ }
+
+ mask = pow(mask*1.5f, (0.5f + automasking->settings.concave_factor) * 8.0);
+ CLAMP(mask, 0.0f, 1.0f);
+ }
+
+ if (automasking->factor) {
+ return mask;
}
if (automasking->settings.flags & BRUSH_AUTOMASKING_FACE_SETS) {
@@ -157,7 +190,7 @@ float SCULPT_automasking_factor_get(AutomaskingCache *automasking, SculptSession
}
}
- return 1.0f;
+ return mask;
}
void SCULPT_automasking_cache_free(AutomaskingCache *automasking)
@@ -191,16 +224,19 @@ typedef struct AutomaskFloodFillData {
char symm;
} AutomaskFloodFillData;
-static bool automask_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool UNUSED(is_duplicate), void *userdata)
+static bool automask_floodfill_cb(SculptSession *ss,
+ SculptVertRef from_vref,
+ SculptVertRef to_vref,
+ bool UNUSED(is_duplicate),
+ void *userdata)
{
AutomaskFloodFillData *data = userdata;
- data->automask_factor[to_v] = 1.0f;
- data->automask_factor[from_v] = 1.0f;
+ data->automask_factor[BKE_pbvh_vertex_index_to_table(ss->pbvh, to_vref)] = 1.0f;
+ data->automask_factor[BKE_pbvh_vertex_index_to_table(ss->pbvh, from_vref)] = 1.0f;
return (!data->use_radius ||
SCULPT_is_vertex_inside_brush_radius_symm(
- SCULPT_vertex_co_get(ss, to_v), data->location, data->radius, data->symm));
+ SCULPT_vertex_co_get(ss, to_vref), data->location, data->radius, data->symm));
}
static float *SCULPT_topology_automasking_init(Sculpt *sd, Object *ob, float *automask_factor)
@@ -255,7 +291,9 @@ static float *sculpt_face_sets_automasking_init(Sculpt *sd, Object *ob, float *a
int tot_vert = SCULPT_vertex_count_get(ss);
int active_face_set = SCULPT_active_face_set_get(ss);
for (int i = 0; i < tot_vert; i++) {
- if (!SCULPT_vertex_has_face_set(ss, i, active_face_set)) {
+ SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
+ if (!SCULPT_vertex_has_face_set(ss, vertex, active_face_set)) {
automask_factor[i] *= 0.0f;
}
}
@@ -281,15 +319,17 @@ float *SCULPT_boundary_automasking_init(Object *ob,
int *edge_distance = MEM_callocN(sizeof(int) * totvert, "automask_factor");
for (int i = 0; i < totvert; i++) {
+ SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
edge_distance[i] = EDGE_DISTANCE_INF;
switch (mode) {
case AUTOMASK_INIT_BOUNDARY_EDGES:
- if (SCULPT_vertex_is_boundary(ss, i)) {
+ if (SCULPT_vertex_is_boundary(ss, vertex)) {
edge_distance[i] = 0;
}
break;
case AUTOMASK_INIT_BOUNDARY_FACE_SETS:
- if (!SCULPT_vertex_has_unique_face_set(ss, i)) {
+ if (!SCULPT_vertex_has_unique_face_set(ss, vertex)) {
edge_distance[i] = 0;
}
break;
@@ -298,11 +338,13 @@ float *SCULPT_boundary_automasking_init(Object *ob,
for (int propagation_it = 0; propagation_it < propagation_steps; propagation_it++) {
for (int i = 0; i < totvert; i++) {
+ SculptVertRef vref = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
if (edge_distance[i] != EDGE_DISTANCE_INF) {
continue;
}
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vref, ni) {
if (edge_distance[ni.index] == propagation_it) {
edge_distance[i] = propagation_it + 1;
}
@@ -330,7 +372,65 @@ static void SCULPT_automasking_cache_settings_update(AutomaskingCache *automaski
Brush *brush)
{
automasking->settings.flags = sculpt_automasking_mode_effective_bits(sd, brush);
+
+ if (brush->concave_mask_factor != 0.0f) {
+ automasking->settings.flags |= BRUSH_AUTOMASKING_CONCAVITY;
+ }
+
automasking->settings.initial_face_set = SCULPT_active_face_set_get(ss);
+ automasking->settings.concave_factor = brush->concave_mask_factor;
+}
+
+float SCULPT_calc_concavity(SculptSession *ss, SculptVertRef vref)
+{
+ SculptVertexNeighborIter ni;
+ float co[3], tot = 0.0, elen = 0.0;
+ const float *vco = SCULPT_vertex_co_get(ss, vref);
+
+ zero_v3(co);
+
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vref, ni) {
+ const float *vco2 = SCULPT_vertex_co_get(ss, ni.vertex);
+
+ elen += len_v3v3(vco, vco2);
+ add_v3_v3(co, vco2);
+ tot += 1.0f;
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ if (!tot) {
+ return 0.5f;
+ }
+
+ elen /= tot;
+ mul_v3_fl(co, 1.0 / tot);
+ sub_v3_v3(co, vco);
+ mul_v3_fl(co, -1.0 / elen);
+
+ float no[3];
+ SCULPT_vertex_normal_get(ss, vref, no);
+
+ float f = dot_v3v3(co, no) * 0.5 + 0.5;
+ return 1.0 - f;
+}
+
+static void SCULPT_concavity_automasking_init(Object *ob, Brush *brush, float *factor)
+{
+ SculptSession *ss = ob->sculpt;
+
+ if (!ss) {
+ return;
+ }
+
+ const int totvert = SCULPT_vertex_count_get(ss);
+
+ for (int i = 0; i < totvert; i++) {
+ SculptVertRef vref = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+ float f = SCULPT_calc_concavity(ss, vref);
+
+ factor[i] *= f;
+ }
+ // BKE_pbvh_vertex_iter_begin
}
AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object *ob)
@@ -378,6 +478,10 @@ AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object
SCULPT_boundary_automasking_init(
ob, AUTOMASK_INIT_BOUNDARY_FACE_SETS, boundary_propagation_steps, automasking->factor);
}
+ if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_CONCAVITY)) {
+ SCULPT_vertex_random_access_ensure(ss);
+ SCULPT_concavity_automasking_init(ob, brush, automasking->factor);
+ }
return automasking;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c
index f1fb402ae41..a92b14eb661 100644
--- a/source/blender/editors/sculpt_paint/sculpt_boundary.c
+++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c
@@ -62,19 +62,28 @@
#define BOUNDARY_STEPS_NONE -1
typedef struct BoundaryInitialVertexFloodFillData {
- int initial_vertex;
+ SculptVertRef initial_vertex;
+ int initial_vertex_index;
int boundary_initial_vertex_steps;
- int boundary_initial_vertex;
+
+ SculptVertRef boundary_initial_vertex;
+
int *floodfill_steps;
float radius_sq;
} BoundaryInitialVertexFloodFillData;
-static bool boundary_initial_vertex_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+static bool boundary_initial_vertex_floodfill_cb(SculptSession *ss,
+ SculptVertRef from_vref,
+ SculptVertRef to_vref,
+ bool is_duplicate,
+ void *userdata)
{
BoundaryInitialVertexFloodFillData *data = userdata;
- if (!SCULPT_vertex_visible_get(ss, to_v)) {
+ int to_v = BKE_pbvh_vertex_index_to_table(ss->pbvh, to_vref);
+ int from_v = BKE_pbvh_vertex_index_to_table(ss->pbvh, from_vref);
+
+ if (!SCULPT_vertex_visible_get(ss, to_vref)) {
return false;
}
@@ -85,23 +94,25 @@ static bool boundary_initial_vertex_floodfill_cb(
data->floodfill_steps[to_v] = data->floodfill_steps[from_v];
}
- if (SCULPT_vertex_is_boundary(ss, to_v)) {
+ if (SCULPT_vertex_is_boundary(ss, to_vref)) {
if (data->floodfill_steps[to_v] < data->boundary_initial_vertex_steps) {
data->boundary_initial_vertex_steps = data->floodfill_steps[to_v];
- data->boundary_initial_vertex = to_v;
+ data->boundary_initial_vertex = to_vref;
}
}
const float len_sq = len_squared_v3v3(SCULPT_vertex_co_get(ss, data->initial_vertex),
- SCULPT_vertex_co_get(ss, to_v));
+ SCULPT_vertex_co_get(ss, to_vref));
return len_sq < data->radius_sq;
}
/* From a vertex index anywhere in the mesh, returns the closest vertex in a mesh boundary inside
* the given radius, if it exists. */
-static int sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss,
- const int initial_vertex,
- const float radius)
+static SculptVertRef sculpt_boundary_get_closest_boundary_vertex(
+ SculptSession *ss,
+ const SculptVertRef initial_vertex,
+ const int initial_vertex_index,
+ const float radius)
{
if (SCULPT_vertex_is_boundary(ss, initial_vertex)) {
@@ -114,6 +125,7 @@ static int sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss,
BoundaryInitialVertexFloodFillData fdata = {
.initial_vertex = initial_vertex,
+ .initial_vertex_index = initial_vertex_index,
.boundary_initial_vertex = BOUNDARY_VERTEX_NONE,
.boundary_initial_vertex_steps = INT_MAX,
.radius_sq = radius * radius,
@@ -134,28 +146,37 @@ static int sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss,
* deformations usually need in the boundary. */
static int BOUNDARY_INDICES_BLOCK_SIZE = 300;
-static void sculpt_boundary_index_add(SculptBoundary *boundary,
- const int new_index,
+static void sculpt_boundary_index_add(SculptSession *ss,
+ SculptBoundary *boundary,
+ const SculptVertRef new_index,
const float distance,
GSet *included_vertices)
{
boundary->vertices[boundary->num_vertices] = new_index;
+ boundary->vertex_indices[boundary->num_vertices] = BKE_pbvh_vertex_index_to_table(ss->pbvh,
+ new_index);
+
if (boundary->distance) {
- boundary->distance[new_index] = distance;
+ boundary->distance[BKE_pbvh_vertex_index_to_table(ss->pbvh, new_index)] = distance;
}
if (included_vertices) {
- BLI_gset_add(included_vertices, POINTER_FROM_INT(new_index));
+ BLI_gset_add(included_vertices, POINTER_FROM_INT(new_index.i));
}
boundary->num_vertices++;
if (boundary->num_vertices >= boundary->vertices_capacity) {
boundary->vertices_capacity += BOUNDARY_INDICES_BLOCK_SIZE;
- boundary->vertices = MEM_reallocN_id(
- boundary->vertices, boundary->vertices_capacity * sizeof(int), "boundary indices");
+ boundary->vertices = MEM_reallocN_id(boundary->vertices,
+ boundary->vertices_capacity * sizeof(SculptVertRef),
+ "boundary vertrefs");
+ boundary->vertex_indices = MEM_reallocN_id(
+ boundary->vertex_indices, boundary->vertices_capacity * sizeof(int), "boundary indices");
}
};
-static void sculpt_boundary_preview_edge_add(SculptBoundary *boundary, const int v1, const int v2)
+static void sculpt_boundary_preview_edge_add(SculptBoundary *boundary,
+ const SculptVertRef v1,
+ const SculptVertRef v2)
{
boundary->edges[boundary->num_edges].v1 = v1;
@@ -175,7 +196,7 @@ static void sculpt_boundary_preview_edge_add(SculptBoundary *boundary, const int
* as well as to check if the initial vertex is valid.
*/
static bool sculpt_boundary_is_vertex_in_editable_boundary(SculptSession *ss,
- const int initial_vertex)
+ const SculptVertRef initial_vertex)
{
if (!SCULPT_vertex_visible_get(ss, initial_vertex)) {
@@ -186,9 +207,9 @@ static bool sculpt_boundary_is_vertex_in_editable_boundary(SculptSession *ss,
int boundary_vertex_count = 0;
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, initial_vertex, ni) {
- if (SCULPT_vertex_visible_get(ss, ni.index)) {
+ if (SCULPT_vertex_visible_get(ss, ni.vertex)) {
neighbor_count++;
- if (SCULPT_vertex_is_boundary(ss, ni.index)) {
+ if (SCULPT_vertex_is_boundary(ss, ni.vertex)) {
boundary_vertex_count++;
}
}
@@ -218,24 +239,27 @@ typedef struct BoundaryFloodFillData {
GSet *included_vertices;
EdgeSet *preview_edges;
- int last_visited_vertex;
+ SculptVertRef last_visited_vertex;
} BoundaryFloodFillData;
static bool boundary_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+ SculptSession *ss, SculptVertRef from_v, SculptVertRef to_v, bool is_duplicate, void *userdata)
{
BoundaryFloodFillData *data = userdata;
SculptBoundary *boundary = data->boundary;
+ int from_v_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, from_v);
+ int to_v_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, to_v);
+
if (!SCULPT_vertex_is_boundary(ss, to_v)) {
return false;
}
const float edge_len = len_v3v3(SCULPT_vertex_co_get(ss, from_v),
SCULPT_vertex_co_get(ss, to_v));
const float distance_boundary_to_dst = boundary->distance ?
- boundary->distance[from_v] + edge_len :
+ boundary->distance[from_v_i] + edge_len :
0.0f;
- sculpt_boundary_index_add(boundary, to_v, distance_boundary_to_dst, data->included_vertices);
+ sculpt_boundary_index_add(ss, boundary, to_v, distance_boundary_to_dst, data->included_vertices);
if (!is_duplicate) {
sculpt_boundary_preview_edge_add(boundary, from_v, to_v);
}
@@ -245,12 +269,15 @@ static bool boundary_floodfill_cb(
static void sculpt_boundary_indices_init(SculptSession *ss,
SculptBoundary *boundary,
const bool init_boundary_distances,
- const int initial_boundary_index)
+ const SculptVertRef initial_boundary_index)
{
const int totvert = SCULPT_vertex_count_get(ss);
boundary->vertices = MEM_malloc_arrayN(
+ BOUNDARY_INDICES_BLOCK_SIZE, sizeof(SculptVertRef), "boundary vrefs");
+ boundary->vertex_indices = MEM_malloc_arrayN(
BOUNDARY_INDICES_BLOCK_SIZE, sizeof(int), "boundary indices");
+
if (init_boundary_distances) {
boundary->distance = MEM_calloc_arrayN(totvert, sizeof(float), "boundary distances");
}
@@ -264,7 +291,7 @@ static void sculpt_boundary_indices_init(SculptSession *ss,
boundary->initial_vertex = initial_boundary_index;
copy_v3_v3(boundary->initial_vertex_position,
SCULPT_vertex_co_get(ss, boundary->initial_vertex));
- sculpt_boundary_index_add(boundary, initial_boundary_index, 0.0f, included_vertices);
+ sculpt_boundary_index_add(ss, boundary, initial_boundary_index, 0.0f, included_vertices);
SCULPT_floodfill_add_initial(&flood, initial_boundary_index);
BoundaryFloodFillData fdata = {
@@ -278,13 +305,13 @@ static void sculpt_boundary_indices_init(SculptSession *ss,
SCULPT_floodfill_free(&flood);
/* Check if the boundary loops into itself and add the extra preview edge to close the loop. */
- if (fdata.last_visited_vertex != BOUNDARY_VERTEX_NONE &&
+ if (fdata.last_visited_vertex.i != BOUNDARY_VERTEX_NONE &&
sculpt_boundary_is_vertex_in_editable_boundary(ss, fdata.last_visited_vertex)) {
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, fdata.last_visited_vertex, ni) {
- if (BLI_gset_haskey(included_vertices, POINTER_FROM_INT(ni.index)) &&
- sculpt_boundary_is_vertex_in_editable_boundary(ss, ni.index)) {
- sculpt_boundary_preview_edge_add(boundary, fdata.last_visited_vertex, ni.index);
+ if (BLI_gset_haskey(included_vertices, POINTER_FROM_INT(ni.vertex.i)) &&
+ sculpt_boundary_is_vertex_in_editable_boundary(ss, ni.vertex)) {
+ sculpt_boundary_preview_edge_add(boundary, fdata.last_visited_vertex, ni.vertex);
boundary->forms_loop = true;
}
}
@@ -302,7 +329,7 @@ static void sculpt_boundary_indices_init(SculptSession *ss,
*/
static void sculpt_boundary_edit_data_init(SculptSession *ss,
SculptBoundary *boundary,
- const int initial_vertex,
+ const SculptVertRef initial_vertex,
const float radius)
{
const int totvert = SCULPT_vertex_count_get(ss);
@@ -313,19 +340,22 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss,
totvert, sizeof(SculptBoundaryEditInfo), "Boundary edit info");
for (int i = 0; i < totvert; i++) {
- boundary->edit_info[i].original_vertex = BOUNDARY_VERTEX_NONE;
+ boundary->edit_info[i].original_vertex.i = BOUNDARY_VERTEX_NONE;
+ boundary->edit_info[i].original_vertex_i = BOUNDARY_VERTEX_NONE;
boundary->edit_info[i].num_propagation_steps = BOUNDARY_STEPS_NONE;
}
- GSQueue *current_iteration = BLI_gsqueue_new(sizeof(int));
- GSQueue *next_iteration = BLI_gsqueue_new(sizeof(int));
+ GSQueue *current_iteration = BLI_gsqueue_new(sizeof(SculptVertRef));
+ GSQueue *next_iteration = BLI_gsqueue_new(sizeof(SculptVertRef));
/* Initialized the first iteration with the vertices already in the boundary. This is propagation
* step 0. */
BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_vertices");
for (int i = 0; i < boundary->num_vertices; i++) {
- boundary->edit_info[boundary->vertices[i]].original_vertex = boundary->vertices[i];
- boundary->edit_info[boundary->vertices[i]].num_propagation_steps = 0;
+ boundary->edit_info[boundary->vertex_indices[i]].original_vertex = boundary->vertices[i];
+ boundary->edit_info[boundary->vertex_indices[i]].original_vertex_i =
+ boundary->vertex_indices[i];
+ boundary->edit_info[boundary->vertex_indices[i]].num_propagation_steps = 0;
/* This ensures that all duplicate vertices in the boundary have the same original_vertex
* index, so the deformation for them will be the same. */
@@ -333,7 +363,11 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss,
SculptVertexNeighborIter ni_duplis;
SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, boundary->vertices[i], ni_duplis) {
if (ni_duplis.is_duplicate) {
- boundary->edit_info[ni_duplis.index].original_vertex = boundary->vertices[i];
+ int index = ni_duplis.index;
+
+ boundary->edit_info[index].original_vertex = boundary->vertices[i];
+ boundary->edit_info[index].original_vertex_i = BKE_pbvh_vertex_index_to_table(
+ ss->pbvh, boundary->vertices[i]);
}
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni_duplis);
@@ -354,29 +388,31 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss,
}
while (!BLI_gsqueue_is_empty(current_iteration)) {
- int from_v;
+ SculptVertRef from_v;
BLI_gsqueue_pop(current_iteration, &from_v);
+ const int from_v_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, from_v);
SculptVertexNeighborIter ni;
SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) {
- const bool is_visible = SCULPT_vertex_visible_get(ss, ni.index);
+
+ const bool is_visible = SCULPT_vertex_visible_get(ss, ni.vertex);
if (!is_visible ||
boundary->edit_info[ni.index].num_propagation_steps != BOUNDARY_STEPS_NONE) {
continue;
}
boundary->edit_info[ni.index].original_vertex =
- boundary->edit_info[from_v].original_vertex;
+ boundary->edit_info[from_v_i].original_vertex;
BLI_BITMAP_ENABLE(visited_vertices, ni.index);
if (ni.is_duplicate) {
/* Grids duplicates handling. */
boundary->edit_info[ni.index].num_propagation_steps =
- boundary->edit_info[from_v].num_propagation_steps;
+ boundary->edit_info[from_v_i].num_propagation_steps;
}
else {
boundary->edit_info[ni.index].num_propagation_steps =
- boundary->edit_info[from_v].num_propagation_steps + 1;
+ boundary->edit_info[from_v_i].num_propagation_steps + 1;
BLI_gsqueue_push(next_iteration, &ni.index);
@@ -386,12 +422,12 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss,
* copy the data in the from_v neighbor iterator. */
if (has_duplicates) {
SculptVertexNeighborIter ni_duplis;
- SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, ni.index, ni_duplis) {
+ SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, ni.vertex, ni_duplis) {
if (ni_duplis.is_duplicate) {
boundary->edit_info[ni_duplis.index].original_vertex =
- boundary->edit_info[from_v].original_vertex;
+ boundary->edit_info[from_v_i].original_vertex;
boundary->edit_info[ni_duplis.index].num_propagation_steps =
- boundary->edit_info[from_v].num_propagation_steps + 1;
+ boundary->edit_info[from_v_i].num_propagation_steps + 1;
}
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni_duplis);
@@ -399,11 +435,11 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss,
/* Check the distance using the vertex that was propagated from the initial vertex that
* was used to initialize the boundary. */
- if (boundary->edit_info[from_v].original_vertex == initial_vertex) {
- boundary->pivot_vertex = ni.index;
- copy_v3_v3(boundary->initial_pivot_position, SCULPT_vertex_co_get(ss, ni.index));
+ if (boundary->edit_info[from_v_i].original_vertex.i == initial_vertex.i) {
+ boundary->pivot_vertex = ni.vertex;
+ copy_v3_v3(boundary->initial_pivot_position, SCULPT_vertex_co_get(ss, ni.vertex));
accum_distance += len_v3v3(SCULPT_vertex_co_get(ss, from_v),
- SCULPT_vertex_co_get(ss, ni.index));
+ SCULPT_vertex_co_get(ss, ni.vertex));
}
}
}
@@ -412,7 +448,7 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss,
/* Copy the new vertices to the queue to be processed in the next iteration. */
while (!BLI_gsqueue_is_empty(next_iteration)) {
- int next_v;
+ SculptVertRef next_v;
BLI_gsqueue_pop(next_iteration, &next_v);
BLI_gsqueue_push(current_iteration, &next_v);
}
@@ -443,7 +479,7 @@ static void sculpt_boundary_falloff_factor_init(SculptSession *ss,
brush, boundary->edit_info[i].num_propagation_steps, boundary->max_propagation_steps);
}
- if (boundary->edit_info[i].original_vertex == boundary->initial_vertex) {
+ if (boundary->edit_info[i].original_vertex.i == boundary->initial_vertex.i) {
/* All vertices that are propagated from the original vertex won't be affected by the
* boundary falloff, so there is no need to calculate anything else. */
continue;
@@ -455,7 +491,8 @@ static void sculpt_boundary_falloff_factor_init(SculptSession *ss,
continue;
}
- const float boundary_distance = boundary->distance[boundary->edit_info[i].original_vertex];
+ const float boundary_distance = boundary->distance[BKE_pbvh_vertex_index_to_table(
+ ss->pbvh, boundary->edit_info[i].original_vertex)];
float falloff_distance = 0.0f;
float direction = 1.0f;
@@ -491,22 +528,22 @@ static void sculpt_boundary_falloff_factor_init(SculptSession *ss,
* return NULL if there is no boundary from the given vertex using the given radius. */
SculptBoundary *SCULPT_boundary_data_init(Object *object,
Brush *brush,
- const int initial_vertex,
+ const SculptVertRef initial_vertex,
const float radius)
{
SculptSession *ss = object->sculpt;
- if (initial_vertex == BOUNDARY_VERTEX_NONE) {
+ if (initial_vertex.i == BOUNDARY_VERTEX_NONE) {
return NULL;
}
SCULPT_vertex_random_access_ensure(ss);
SCULPT_boundary_info_ensure(object);
- const int boundary_initial_vertex = sculpt_boundary_get_closest_boundary_vertex(
- ss, initial_vertex, radius);
+ const SculptVertRef boundary_initial_vertex = sculpt_boundary_get_closest_boundary_vertex(
+ ss, initial_vertex, BKE_pbvh_vertex_index_to_table(ss->pbvh, initial_vertex), radius);
- if (boundary_initial_vertex == BOUNDARY_VERTEX_NONE) {
+ if (boundary_initial_vertex.i == BOUNDARY_VERTEX_NONE) {
return NULL;
}
@@ -555,30 +592,34 @@ static void sculpt_boundary_bend_data_init(SculptSession *ss, SculptBoundary *bo
totvert, 3 * sizeof(float), "pivot positions");
for (int i = 0; i < totvert; i++) {
+ SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
if (boundary->edit_info[i].num_propagation_steps != boundary->max_propagation_steps) {
continue;
}
+
float dir[3];
float normal[3];
- SCULPT_vertex_normal_get(ss, i, normal);
+ SCULPT_vertex_normal_get(ss, vertex, normal);
sub_v3_v3v3(dir,
SCULPT_vertex_co_get(ss, boundary->edit_info[i].original_vertex),
- SCULPT_vertex_co_get(ss, i));
+ SCULPT_vertex_co_get(ss, vertex));
cross_v3_v3v3(
- boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex], dir, normal);
- normalize_v3(boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex]);
- copy_v3_v3(boundary->bend.pivot_positions[boundary->edit_info[i].original_vertex],
- SCULPT_vertex_co_get(ss, i));
+ boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex_i], dir, normal);
+ normalize_v3(boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex_i]);
+ copy_v3_v3(boundary->bend.pivot_positions[boundary->edit_info[i].original_vertex_i],
+ SCULPT_vertex_co_get(ss, vertex));
}
for (int i = 0; i < totvert; i++) {
if (boundary->edit_info[i].num_propagation_steps == BOUNDARY_STEPS_NONE) {
continue;
}
+
copy_v3_v3(boundary->bend.pivot_positions[i],
- boundary->bend.pivot_positions[boundary->edit_info[i].original_vertex]);
+ boundary->bend.pivot_positions[boundary->edit_info[i].original_vertex_i]);
copy_v3_v3(boundary->bend.pivot_rotation_axis[i],
- boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex]);
+ boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex_i]);
}
}
@@ -588,12 +629,15 @@ static void sculpt_boundary_slide_data_init(SculptSession *ss, SculptBoundary *b
boundary->slide.directions = MEM_calloc_arrayN(totvert, 3 * sizeof(float), "slide directions");
for (int i = 0; i < totvert; i++) {
+ SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
if (boundary->edit_info[i].num_propagation_steps != boundary->max_propagation_steps) {
}
- sub_v3_v3v3(boundary->slide.directions[boundary->edit_info[i].original_vertex],
+
+ sub_v3_v3v3(boundary->slide.directions[boundary->edit_info[i].original_vertex_i],
SCULPT_vertex_co_get(ss, boundary->edit_info[i].original_vertex),
- SCULPT_vertex_co_get(ss, i));
- normalize_v3(boundary->slide.directions[boundary->edit_info[i].original_vertex]);
+ SCULPT_vertex_co_get(ss, vertex));
+ normalize_v3(boundary->slide.directions[boundary->edit_info[i].original_vertex_i]);
}
for (int i = 0; i < totvert; i++) {
@@ -601,7 +645,7 @@ static void sculpt_boundary_slide_data_init(SculptSession *ss, SculptBoundary *b
continue;
}
copy_v3_v3(boundary->slide.directions[i],
- boundary->slide.directions[boundary->edit_info[i].original_vertex]);
+ boundary->slide.directions[boundary->edit_info[i].original_vertex_i]);
}
}
@@ -656,7 +700,7 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
const float disp = strength * sculpt_boundary_displacement_from_grab_delta_get(ss, boundary);
float angle_factor = disp / ss->cache->radius;
@@ -679,7 +723,7 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata,
}
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
- const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index);
+ const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex);
float t_orig_co[3];
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
sub_v3_v3v3(t_orig_co, orig_data.co, boundary->bend.pivot_positions[vd.index]);
@@ -711,7 +755,7 @@ static void do_boundary_brush_slide_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
const float disp = sculpt_boundary_displacement_from_grab_delta_get(ss, boundary);
@@ -728,7 +772,7 @@ static void do_boundary_brush_slide_task_cb_ex(void *__restrict userdata,
}
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
- const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index);
+ const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex);
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
madd_v3_v3v3fl(target_co,
orig_data.co,
@@ -758,7 +802,7 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
const float disp = sculpt_boundary_displacement_from_grab_delta_get(ss, boundary);
@@ -775,7 +819,7 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata,
}
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
- const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index);
+ const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex);
float normal[3];
normal_short_to_float_v3(normal, orig_data.no);
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
@@ -807,7 +851,7 @@ static void do_boundary_brush_grab_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -822,7 +866,7 @@ static void do_boundary_brush_grab_task_cb_ex(void *__restrict userdata,
}
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
- const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index);
+ const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex);
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
madd_v3_v3v3fl(target_co,
orig_data.co,
@@ -851,7 +895,7 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
const float disp = strength * sculpt_boundary_displacement_from_grab_delta_get(ss, boundary);
float angle_factor = disp / ss->cache->radius;
@@ -874,7 +918,7 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata,
}
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
- const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index);
+ const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex);
float t_orig_co[3];
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
sub_v3_v3v3(t_orig_co, orig_data.co, boundary->twist.pivot_position);
@@ -906,7 +950,7 @@ static void do_boundary_brush_smooth_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -924,9 +968,9 @@ static void do_boundary_brush_smooth_task_cb_ex(void *__restrict userdata,
int total_neighbors = 0;
const int current_propagation_steps = boundary->edit_info[vd.index].num_propagation_steps;
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
if (current_propagation_steps == boundary->edit_info[ni.index].num_propagation_steps) {
- add_v3_v3(coord_accum, SCULPT_vertex_co_get(ss, ni.index));
+ add_v3_v3(coord_accum, SCULPT_vertex_co_get(ss, ni.vertex));
total_neighbors++;
}
}
@@ -960,7 +1004,8 @@ void SCULPT_do_boundary_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totn
const int symm_area = ss->cache->mirror_symmetry_pass;
if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
- int initial_vertex;
+ SculptVertRef initial_vertex;
+
if (ss->cache->mirror_symmetry_pass == 0) {
initial_vertex = SCULPT_active_vertex_get(ss);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c
index 16d10f6d6bb..5760e4e9e10 100644
--- a/source/blender/editors/sculpt_paint/sculpt_cloth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c
@@ -219,20 +219,25 @@ static void cloth_brush_reallocate_constraints(SculptClothSimulation *cloth_sim)
static void cloth_brush_add_length_constraint(SculptSession *ss,
SculptClothSimulation *cloth_sim,
const int node_index,
- const int v1,
- const int v2,
+ const int v1i,
+ const int v2i,
const bool use_persistent)
{
SculptClothLengthConstraint *length_constraint =
&cloth_sim->length_constraints[cloth_sim->tot_length_constraints];
- length_constraint->elem_index_a = v1;
- length_constraint->elem_index_b = v2;
+ SculptVertRef v1, v2;
+
+ v1 = BKE_pbvh_table_index_to_vertex(ss->pbvh, v1i);
+ v2 = BKE_pbvh_table_index_to_vertex(ss->pbvh, v2i);
+
+ length_constraint->elem_index_a = v1i;
+ length_constraint->elem_index_b = v2i;
length_constraint->node = node_index;
- length_constraint->elem_position_a = cloth_sim->pos[v1];
- length_constraint->elem_position_b = cloth_sim->pos[v2];
+ length_constraint->elem_position_a = cloth_sim->pos[v1i];
+ length_constraint->elem_position_b = cloth_sim->pos[v2i];
length_constraint->type = SCULPT_CLOTH_CONSTRAINT_STRUCTURAL;
@@ -252,7 +257,7 @@ static void cloth_brush_add_length_constraint(SculptSession *ss,
cloth_brush_reallocate_constraints(cloth_sim);
/* Add the constraint to the #GSet to avoid creating it again. */
- BLI_edgeset_add(cloth_sim->created_length_constraints, v1, v2);
+ BLI_edgeset_add(cloth_sim->created_length_constraints, v1i, v2i);
}
static void cloth_brush_add_softbody_constraint(SculptClothSimulation *cloth_sim,
@@ -387,7 +392,7 @@ static void do_cloth_brush_build_constraints_task_cb_ex(
int tot_indices = 0;
build_indices[tot_indices] = vd.index;
tot_indices++;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
build_indices[tot_indices] = ni.index;
tot_indices++;
}
@@ -558,7 +563,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
float brush_disp[3];
@@ -806,7 +811,7 @@ static void do_cloth_brush_solve_simulation_task_cb_ex(
mul_v3_fl(pos_diff, (1.0f - cloth_sim->damping) * sim_factor);
const float mask_v = (1.0f - (vd.mask ? *vd.mask : 0.0f)) *
- SCULPT_automasking_factor_get(automasking, ss, vd.index);
+ SCULPT_automasking_factor_get(automasking, ss, vd.vertex);
madd_v3_v3fl(cloth_sim->pos[i], pos_diff, mask_v);
madd_v3_v3fl(cloth_sim->pos[i], cloth_sim->acceleration[i], mask_v);
@@ -852,6 +857,9 @@ static void cloth_brush_satisfy_constraints(SculptSession *ss,
const int v1 = constraint->elem_index_a;
const int v2 = constraint->elem_index_b;
+ const SculptVertRef v1ref = BKE_pbvh_table_index_to_vertex(ss->pbvh, v1);
+ const SculptVertRef v2ref = BKE_pbvh_table_index_to_vertex(ss->pbvh, v2);
+
float v1_to_v2[3];
sub_v3_v3v3(v1_to_v2, constraint->elem_position_b, constraint->elem_position_a);
const float current_distance = len_v3(v1_to_v2);
@@ -874,10 +882,10 @@ static void cloth_brush_satisfy_constraints(SculptSession *ss,
mul_v3_v3fl(correction_vector_half, correction_vector, 0.5f);
- const float mask_v1 = (1.0f - SCULPT_vertex_mask_get(ss, v1)) *
- SCULPT_automasking_factor_get(automasking, ss, v1);
- const float mask_v2 = (1.0f - SCULPT_vertex_mask_get(ss, v2)) *
- SCULPT_automasking_factor_get(automasking, ss, v2);
+ const float mask_v1 = (1.0f - SCULPT_vertex_mask_get(ss, v1ref)) *
+ SCULPT_automasking_factor_get(automasking, ss, v1ref);
+ const float mask_v2 = (1.0f - SCULPT_vertex_mask_get(ss, v2ref)) *
+ SCULPT_automasking_factor_get(automasking, ss, v2ref);
float sim_location[3];
cloth_brush_simulation_location_get(ss, brush, sim_location);
@@ -1150,16 +1158,20 @@ void SCULPT_cloth_brush_simulation_init(SculptSession *ss, SculptClothSimulation
const int totverts = SCULPT_vertex_count_get(ss);
const bool has_deformation_pos = cloth_sim->deformation_pos != NULL;
const bool has_softbody_pos = cloth_sim->softbody_pos != NULL;
+ SCULPT_vertex_random_access_ensure(ss);
+
for (int i = 0; i < totverts; i++) {
- copy_v3_v3(cloth_sim->last_iteration_pos[i], SCULPT_vertex_co_get(ss, i));
- copy_v3_v3(cloth_sim->init_pos[i], SCULPT_vertex_co_get(ss, i));
- copy_v3_v3(cloth_sim->prev_pos[i], SCULPT_vertex_co_get(ss, i));
+ SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
+ copy_v3_v3(cloth_sim->last_iteration_pos[i], SCULPT_vertex_co_get(ss, vertex));
+ copy_v3_v3(cloth_sim->init_pos[i], SCULPT_vertex_co_get(ss, vertex));
+ copy_v3_v3(cloth_sim->prev_pos[i], SCULPT_vertex_co_get(ss, vertex));
if (has_deformation_pos) {
- copy_v3_v3(cloth_sim->deformation_pos[i], SCULPT_vertex_co_get(ss, i));
+ copy_v3_v3(cloth_sim->deformation_pos[i], SCULPT_vertex_co_get(ss, vertex));
cloth_sim->deformation_strength[i] = 1.0f;
}
if (has_softbody_pos) {
- copy_v3_v3(cloth_sim->softbody_pos[i], SCULPT_vertex_co_get(ss, i));
+ copy_v3_v3(cloth_sim->softbody_pos[i], SCULPT_vertex_co_get(ss, vertex));
}
}
}
@@ -1168,7 +1180,9 @@ void SCULPT_cloth_brush_store_simulation_state(SculptSession *ss, SculptClothSim
{
const int totverts = SCULPT_vertex_count_get(ss);
for (int i = 0; i < totverts; i++) {
- copy_v3_v3(cloth_sim->pos[i], SCULPT_vertex_co_get(ss, i));
+ SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
+ copy_v3_v3(cloth_sim->pos[i], SCULPT_vertex_co_get(ss, vertex));
}
}
@@ -1452,13 +1466,13 @@ static void cloth_filter_apply_forces_task_cb(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
{
float fade = vd.mask ? *vd.mask : 0.0f;
- fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.index);
+ fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex);
fade = 1.0f - fade;
float force[3] = {0.0f, 0.0f, 0.0f};
float disp[3], temp[3], transform[3][3];
if (ss->filter_cache->active_face_set != SCULPT_FACE_SET_NONE) {
- if (!SCULPT_vertex_has_face_set(ss, vd.index, ss->filter_cache->active_face_set)) {
+ if (!SCULPT_vertex_has_face_set(ss, vd.vertex, ss->filter_cache->active_face_set)) {
continue;
}
}
@@ -1477,7 +1491,7 @@ static void cloth_filter_apply_forces_task_cb(void *__restrict userdata,
break;
case CLOTH_FILTER_INFLATE: {
float normal[3];
- SCULPT_vertex_normal_get(ss, vd.index, normal);
+ SCULPT_vertex_normal_get(ss, vd.vertex, normal);
mul_v3_v3fl(force, normal, fade * data->filter_strength);
} break;
case CLOTH_FILTER_EXPAND:
@@ -1542,7 +1556,9 @@ static int sculpt_cloth_filter_modal(bContext *C, wmOperator *op, const wmEvent
const int totverts = SCULPT_vertex_count_get(ss);
for (int i = 0; i < totverts; i++) {
- copy_v3_v3(ss->filter_cache->cloth_sim->pos[i], SCULPT_vertex_co_get(ss, i));
+ SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
+ copy_v3_v3(ss->filter_cache->cloth_sim->pos[i], SCULPT_vertex_co_get(ss, vertex));
}
SculptThreadedTaskData data = {
diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c
index ddf7ba1e412..27414a92401 100644
--- a/source/blender/editors/sculpt_paint/sculpt_detail.c
+++ b/source/blender/editors/sculpt_paint/sculpt_detail.c
@@ -109,7 +109,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_COORDS);
while (BKE_pbvh_bmesh_update_topology(
- ss->pbvh, PBVH_Collapse | PBVH_Subdivide, center, NULL, size, false, false)) {
+ ss->pbvh, PBVH_Collapse | PBVH_Subdivide, center, NULL, size, false, false, -1, false)) {
for (int i = 0; i < totnodes; i++) {
BKE_pbvh_node_mark_topology_update(nodes[i]);
}
@@ -167,13 +167,13 @@ static void sample_detail_voxel(bContext *C, ViewContext *vc, int mx, int my)
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false);
/* Average the edge length of the connected edges to the active vertex. */
- int active_vertex = SCULPT_active_vertex_get(ss);
+ SculptVertRef active_vertex = SCULPT_active_vertex_get(ss);
const float *active_vertex_co = SCULPT_active_vertex_co_get(ss);
float edge_length = 0.0f;
int tot = 0;
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, active_vertex, ni) {
- edge_length += len_v3v3(active_vertex_co, SCULPT_vertex_co_get(ss, ni.index));
+ edge_length += len_v3v3(active_vertex_co, SCULPT_vertex_co_get(ss, ni.vertex));
tot += 1;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
index 87e0ea7f6a9..bfd7f843a7e 100644
--- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
@@ -23,6 +23,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_array.h"
#include "BLI_blenlib.h"
#include "BLI_hash.h"
#include "BLI_math.h"
@@ -110,19 +111,102 @@ void SCULPT_pbvh_clear(Object *ob)
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
+void SCULPT_dyntopo_save_origverts(SculptSession *ss)
+{
+ BMIter iter;
+ BMVert *v;
+
+ BM_ITER_MESH (v, &iter, ss->bm, BM_VERTS_OF_MESH) {
+ float *co = BM_ELEM_CD_GET_VOID_P(v, ss->cd_origco_offset);
+ float *no = BM_ELEM_CD_GET_VOID_P(v, ss->cd_origno_offset);
+
+ copy_v3_v3(co, v->co);
+ copy_v3_v3(no, v->no);
+ }
+}
+
+static char layer_id[] = "_dyntopo_node_id";
+static char origco_id[] = "_dyntopop_orig_co";
+static char origno_id[] = "_dyntopop_orig_no";
+static char origcolor_id[] = "_dyntopo_orig_vcol";
+
+void SCULPT_dyntopo_node_layers_update_offsets(SculptSession *ss)
+{
+ SCULPT_dyntopo_node_layers_add(ss);
+}
+
void SCULPT_dyntopo_node_layers_add(SculptSession *ss)
{
- int cd_node_layer_index;
+ int cd_node_layer_index, cd_face_node_layer_index;
+
+ int cd_origco_index, cd_origno_index, cd_origvcol_index = -1;
+ bool have_vcol = CustomData_has_layer(&ss->bm->vdata, CD_PROP_COLOR);
- char layer_id[] = "_dyntopo_node_id";
+ if (have_vcol) {
+ cd_origvcol_index = CustomData_get_named_layer_index(
+ &ss->bm->vdata, CD_PROP_COLOR, origcolor_id);
+
+ if (cd_origvcol_index == -1) {
+ BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_COLOR, origcolor_id);
+ }
+ }
+
+ cd_origco_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_FLOAT3, origco_id);
+ if (cd_origco_index == -1) {
+ BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_FLOAT3, origco_id);
+ }
+
+ cd_origno_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_FLOAT3, origno_id);
+ if (cd_origno_index == -1) {
+ BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_FLOAT3, origno_id);
+ }
cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT32, layer_id);
if (cd_node_layer_index == -1) {
BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_INT32, layer_id);
- cd_node_layer_index = CustomData_get_named_layer_index(
- &ss->bm->vdata, CD_PROP_INT32, layer_id);
}
+ cd_face_node_layer_index = CustomData_get_named_layer_index(
+ &ss->bm->pdata, CD_PROP_INT32, layer_id);
+ if (cd_face_node_layer_index == -1) {
+ BM_data_layer_add_named(ss->bm, &ss->bm->pdata, CD_PROP_INT32, layer_id);
+ }
+
+ // get indices again, as they might have changed after adding new layers
+ cd_origco_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_FLOAT3, origco_id);
+ cd_origno_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_FLOAT3, origno_id);
+ cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT32, layer_id);
+ cd_face_node_layer_index = CustomData_get_named_layer_index(
+ &ss->bm->pdata, CD_PROP_INT32, layer_id);
+
+ if (have_vcol) {
+ cd_origvcol_index = CustomData_get_named_layer_index(
+ &ss->bm->vdata, CD_PROP_COLOR, origcolor_id);
+
+ ss->cd_origvcol_offset = CustomData_get_n_offset(
+ &ss->bm->vdata,
+ CD_PROP_COLOR,
+ cd_origvcol_index - CustomData_get_layer_index(&ss->bm->vdata, CD_PROP_COLOR));
+ ss->bm->vdata.layers[cd_origvcol_index].flag |= CD_FLAG_TEMPORARY;
+ }
+ else {
+ ss->cd_origvcol_offset = -1;
+ }
+
+ ss->cd_origco_offset = CustomData_get_n_offset(
+ &ss->bm->vdata,
+ CD_PROP_FLOAT3,
+ cd_origco_index - CustomData_get_layer_index(&ss->bm->vdata, CD_PROP_FLOAT3));
+ ss->bm->vdata.layers[cd_origco_index].flag |= CD_FLAG_TEMPORARY;
+
+ ss->cd_vcol_offset = CustomData_get_offset(&ss->bm->vdata, CD_PROP_COLOR);
+
+ ss->cd_origno_offset = CustomData_get_n_offset(
+ &ss->bm->vdata,
+ CD_PROP_FLOAT3,
+ cd_origno_index - CustomData_get_layer_index(&ss->bm->vdata, CD_PROP_FLOAT3));
+ ss->bm->vdata.layers[cd_origno_index].flag |= CD_FLAG_TEMPORARY;
+
ss->cd_vert_node_offset = CustomData_get_n_offset(
&ss->bm->vdata,
CD_PROP_INT32,
@@ -130,19 +214,113 @@ void SCULPT_dyntopo_node_layers_add(SculptSession *ss)
ss->bm->vdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY;
- cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->pdata, CD_PROP_INT32, layer_id);
- if (cd_node_layer_index == -1) {
- BM_data_layer_add_named(ss->bm, &ss->bm->pdata, CD_PROP_INT32, layer_id);
- cd_node_layer_index = CustomData_get_named_layer_index(
- &ss->bm->pdata, CD_PROP_INT32, layer_id);
- }
-
ss->cd_face_node_offset = CustomData_get_n_offset(
&ss->bm->pdata,
CD_PROP_INT32,
- cd_node_layer_index - CustomData_get_layer_index(&ss->bm->pdata, CD_PROP_INT32));
+ cd_face_node_layer_index - CustomData_get_layer_index(&ss->bm->pdata, CD_PROP_INT32));
+
+ ss->bm->pdata.layers[cd_face_node_layer_index].flag |= CD_FLAG_TEMPORARY;
+ ss->cd_faceset_offset = CustomData_get_offset(&ss->bm->pdata, CD_SCULPT_FACE_SETS);
- ss->bm->pdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY;
+ SCULPT_dyntopo_save_origverts(ss);
+}
+
+/**
+ Syncs customdata layers with internal bmesh, but ignores deleted layers.
+*/
+void SCULPT_dynamic_topology_sync_layers(Object *ob, Mesh *me)
+{
+ SculptSession *ss = ob->sculpt;
+
+ if (!ss || !ss->bm) {
+ return;
+ }
+
+ bool modified = false;
+ BMesh *bm = ss->bm;
+
+ CustomData *cd1[4] = {&me->vdata, &me->edata, &me->ldata, &me->pdata};
+ CustomData *cd2[4] = {&bm->vdata, &bm->edata, &bm->ldata, &bm->pdata};
+ int types[4] = {BM_VERT, BM_EDGE, BM_LOOP, BM_FACE};
+ int badmask = CD_MASK_MLOOP | CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MPOLY | CD_MASK_ORIGINDEX |
+ CD_MASK_ORIGSPACE | CD_MASK_MFACE;
+
+ for (int i = 0; i < 4; i++) {
+ CustomDataLayer **newlayers = NULL;
+ BLI_array_declare(newlayers);
+
+ CustomData *data1 = cd1[i];
+ CustomData *data2 = cd2[i];
+
+ if (!data1->layers) {
+ continue;
+ }
+
+ for (int j = 0; j < data1->totlayer; j++) {
+ CustomDataLayer *cl1 = data1->layers + j;
+
+ if ((1 << cl1->type) & badmask) {
+ continue;
+ }
+
+ int idx = CustomData_get_named_layer_index(data2, cl1->type, cl1->name);
+ if (idx < 0) {
+ BLI_array_append(newlayers, cl1);
+ }
+ }
+
+ for (int j = 0; j < BLI_array_len(newlayers); j++) {
+ BM_data_layer_add_named(bm, data2, newlayers[j]->type, newlayers[j]->name);
+ modified |= true;
+ }
+
+ char typemap[CD_NUMTYPES] = {
+ 0,
+ };
+
+ for (int j = 0; j < data1->totlayer; j++) {
+ CustomDataLayer *cl = data1->layers + j;
+ CustomDataLayer *cl1 = cl;
+
+ if ((1 << cl1->type) & badmask) {
+ continue;
+ }
+
+ if (typemap[cl1->type]) {
+ continue;
+ }
+
+ typemap[cl1->type] = 1;
+ cl1 = cl + CustomData_get_active_layer(data1, cl1->type);
+
+ int idx = CustomData_get_named_layer_index(data2, cl1->type, cl1->name);
+ CustomData_set_layer_active_index(data2, cl1->type, idx);
+
+ cl1 = cl + CustomData_get_render_layer(data1, cl1->type);
+ idx = CustomData_get_named_layer_index(data2, cl1->type, cl1->name);
+ CustomData_set_layer_render_index(data2, cl1->type, idx);
+
+ cl1 = cl + CustomData_get_stencil_layer(data1, cl1->type);
+ idx = CustomData_get_named_layer_index(data2, cl1->type, cl1->name);
+ CustomData_set_layer_stencil_index(data2, cl1->type, idx);
+
+ cl1 = cl + CustomData_get_clone_layer(data1, cl1->type);
+ idx = CustomData_get_named_layer_index(data2, cl1->type, cl1->name);
+ CustomData_set_layer_clone_index(data2, cl1->type, idx);
+ }
+
+ BLI_array_free(newlayers);
+ }
+
+ if (modified) {
+ SCULPT_dyntopo_node_layers_update_offsets(ss);
+ BKE_pbvh_update_offsets(ss->pbvh,
+ ss->cd_vert_node_offset,
+ ss->cd_face_node_offset,
+ ss->cd_origco_offset,
+ ss->cd_origno_offset,
+ ss->cd_origvcol_offset);
+ }
}
void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
@@ -165,7 +343,8 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene
.use_toolflags = false,
}));
- BM_mesh_bm_from_me(ss->bm,
+ BM_mesh_bm_from_me(NULL,
+ ss->bm,
me,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
@@ -175,6 +354,30 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene
SCULPT_dynamic_topology_triangulate(ss->bm);
BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
SCULPT_dyntopo_node_layers_add(ss);
+
+ BMIter iter;
+ BMVert *v;
+ int cd_vcol_offset = CustomData_get_offset(&ss->bm->vdata, CD_PROP_COLOR);
+
+ BM_ITER_MESH (v, &iter, ss->bm, BM_VERTS_OF_MESH) {
+ if (ss->cd_origco_offset >= 0) {
+ float *co = BM_ELEM_CD_GET_VOID_P(v, ss->cd_origco_offset);
+ copy_v3_v3(co, v->co);
+ }
+ if (ss->cd_origno_offset >= 0) {
+ float *no = BM_ELEM_CD_GET_VOID_P(v, ss->cd_origno_offset);
+ copy_v3_v3(no, v->no);
+ }
+
+ if (ss->cd_origvcol_offset >= 0) {
+
+ float *ocolor = BM_ELEM_CD_GET_VOID_P(v, ss->cd_origvcol_offset);
+ float *color = BM_ELEM_CD_GET_VOID_P(v, cd_vcol_offset);
+
+ copy_v4_v4(ocolor, color);
+ }
+ }
+
/* Make sure the data for existing faces are initialized. */
if (me->totpoly != ss->bm->totface) {
BM_mesh_normals_update(ss->bm);
@@ -184,7 +387,8 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene
me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
/* Enable logging for undo/redo. */
- ss->bm_log = BM_log_create(ss->bm);
+ ss->bm_log = BM_log_create(
+ ss->bm, ss->cd_origco_offset, ss->cd_origno_offset, ss->cd_origvcol_offset);
/* Update dependency graph, so modifiers that depend on dyntopo being enabled
* are re-evaluated and the PBVH is re-created. */
@@ -233,16 +437,6 @@ static void SCULPT_dynamic_topology_disable_ex(
else {
BKE_sculptsession_bm_to_me(ob, true);
- /* Reset Face Sets as they are no longer valid. */
- if (!CustomData_has_layer(&me->pdata, CD_SCULPT_FACE_SETS)) {
- CustomData_add_layer(&me->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, NULL, me->totpoly);
- }
- ss->face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS);
- for (int i = 0; i < me->totpoly; i++) {
- ss->face_sets[i] = 1;
- }
- me->face_sets_color_default = 1;
-
/* Sync the visibility to vertices manually as the pmap is still not initialized. */
for (int i = 0; i < me->totvert; i++) {
me->mvert[i].flag &= ~ME_HIDE;
@@ -384,6 +578,7 @@ enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob)
BLI_assert(ss->bm == NULL);
UNUSED_VARS_NDEBUG(ss);
+#ifndef DYNTOPO_CD_INTERP
for (int i = 0; i < CD_NUMTYPES; i++) {
if (!ELEM(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX)) {
if (CustomData_has_layer(&me->vdata, i)) {
@@ -397,6 +592,7 @@ enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob)
}
}
}
+#endif
{
VirtualModifierData virtualModifierData;
diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.c b/source/blender/editors/sculpt_paint/sculpt_expand.c
index db6d33c2700..892b30048f6 100644
--- a/source/blender/editors/sculpt_paint/sculpt_expand.c
+++ b/source/blender/editors/sculpt_paint/sculpt_expand.c
@@ -194,7 +194,7 @@ static float sculpt_expand_falloff_value_vertex_get(SculptSession *ss,
}
float rgba[4];
- const float *vertex_co = SCULPT_vertex_co_get(ss, v);
+ const float *vertex_co = SCULPT_vertex_co_get(ss, BKE_pbvh_table_index_to_vertex(ss->pbvh, v));
const float avg = BKE_brush_sample_tex_3d(
expand_cache->scene, expand_cache->brush, vertex_co, rgba, 0, ss->tex_pool);
@@ -227,7 +227,9 @@ static float sculpt_expand_max_vertex_falloff_get(ExpandCache *expand_cache)
*/
static bool sculpt_expand_state_get(SculptSession *ss, ExpandCache *expand_cache, const int v)
{
- if (!SCULPT_vertex_visible_get(ss, v)) {
+ SculptVertRef vref = BKE_pbvh_table_index_to_vertex(ss->pbvh, v);
+
+ if (!SCULPT_vertex_visible_get(ss, vref)) {
return false;
}
@@ -245,7 +247,7 @@ static bool sculpt_expand_state_get(SculptSession *ss, ExpandCache *expand_cache
/* Face Sets are not being modified when using this function, so it is ok to get this directly
* from the Sculpt API instead of implementing a custom function to get them from
* expand_cache->original_face_sets. */
- const int face_set = SCULPT_vertex_face_set_get(ss, v);
+ const int face_set = SCULPT_vertex_face_set_get(ss, vref);
enabled = BLI_gset_haskey(expand_cache->snap_enabled_face_sets, POINTER_FROM_INT(face_set));
}
else {
@@ -381,20 +383,22 @@ static BLI_bitmap *sculpt_expand_boundary_from_enabled(SculptSession *ss,
const int totvert = SCULPT_vertex_count_get(ss);
BLI_bitmap *boundary_vertices = BLI_BITMAP_NEW(totvert, "boundary vertices");
for (int i = 0; i < totvert; i++) {
+ SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
if (!BLI_BITMAP_TEST(enabled_vertices, i)) {
continue;
}
bool is_expand_boundary = false;
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
if (!BLI_BITMAP_TEST(enabled_vertices, ni.index)) {
is_expand_boundary = true;
}
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
- if (use_mesh_boundary && SCULPT_vertex_is_boundary(ss, i)) {
+ if (use_mesh_boundary && SCULPT_vertex_is_boundary(ss, vertex)) {
is_expand_boundary = true;
}
@@ -410,12 +414,13 @@ static BLI_bitmap *sculpt_expand_boundary_from_enabled(SculptSession *ss,
* Utility function to get the closet vertex after flipping an original vertex position based on
* an symmetry pass iteration index.
*/
-static int sculpt_expand_get_vertex_index_for_symmetry_pass(Object *ob,
+static SculptVertRef sculpt_expand_get_vertex_index_for_symmetry_pass(Object *ob,
const char symm_it,
- const int original_vertex)
+ const SculptVertRef original_vertex)
{
SculptSession *ss = ob->sculpt;
- int symm_vertex = SCULPT_EXPAND_VERTEX_NONE;
+ SculptVertRef symm_vertex = {SCULPT_EXPAND_VERTEX_NONE};
+
if (symm_it == 0) {
symm_vertex = original_vertex;
}
@@ -448,20 +453,23 @@ typedef struct ExpandFloodFillData {
} ExpandFloodFillData;
static bool expand_topology_floodfill_cb(
- SculptSession *UNUSED(ss), int from_v, int to_v, bool is_duplicate, void *userdata)
+ SculptSession *ss, SculptVertRef from_v, SculptVertRef to_v, bool is_duplicate, void *userdata)
{
ExpandFloodFillData *data = userdata;
+ int from_v_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, from_v);
+ int to_v_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, to_v);
+
if (!is_duplicate) {
- const float to_it = data->dists[from_v] + 1.0f;
- data->dists[to_v] = to_it;
+ const float to_it = data->dists[from_v_i] + 1.0f;
+ data->dists[to_v_i] = to_it;
}
else {
- data->dists[to_v] = data->dists[from_v];
+ data->dists[to_v_i] = data->dists[from_v_i];
}
return true;
}
-static float *sculpt_expand_topology_falloff_create(Sculpt *sd, Object *ob, const int v)
+static float *sculpt_expand_topology_falloff_create(Sculpt *sd, Object *ob, const SculptVertRef v)
{
SculptSession *ss = ob->sculpt;
const int totvert = SCULPT_vertex_count_get(ss);
@@ -486,23 +494,26 @@ static float *sculpt_expand_topology_falloff_create(Sculpt *sd, Object *ob, cons
* This creates falloff patterns that follow and snap to the hard edges of the object.
*/
static bool mask_expand_normal_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+ SculptSession *ss, SculptVertRef from_v, SculptVertRef to_v, bool is_duplicate, void *userdata)
{
ExpandFloodFillData *data = userdata;
+ int from_v_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, from_v);
+ int to_v_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, to_v);
+
if (!is_duplicate) {
float current_normal[3], prev_normal[3];
SCULPT_vertex_normal_get(ss, to_v, current_normal);
SCULPT_vertex_normal_get(ss, from_v, prev_normal);
- const float from_edge_factor = data->edge_factor[from_v];
- data->edge_factor[to_v] = dot_v3v3(current_normal, prev_normal) * from_edge_factor;
- data->dists[to_v] = dot_v3v3(data->original_normal, current_normal) *
+ const float from_edge_factor = data->edge_factor[from_v_i];
+ data->edge_factor[to_v_i] = dot_v3v3(current_normal, prev_normal) * from_edge_factor;
+ data->dists[to_v_i] = dot_v3v3(data->original_normal, current_normal) *
powf(from_edge_factor, data->edge_sensitivity);
- CLAMP(data->dists[to_v], 0.0f, 1.0f);
+ CLAMP(data->dists[to_v_i], 0.0f, 1.0f);
}
else {
/* PBVH_GRIDS duplicate handling. */
- data->edge_factor[to_v] = data->edge_factor[from_v];
- data->dists[to_v] = data->dists[from_v];
+ data->edge_factor[to_v_i] = data->edge_factor[from_v_i];
+ data->dists[to_v_i] = data->dists[from_v_i];
}
return true;
@@ -510,7 +521,7 @@ static bool mask_expand_normal_floodfill_cb(
static float *sculpt_expand_normal_falloff_create(Sculpt *sd,
Object *ob,
- const int v,
+ const SculptVertRef v,
const float edge_sensitivity)
{
SculptSession *ss = ob->sculpt;
@@ -537,8 +548,10 @@ static float *sculpt_expand_normal_falloff_create(Sculpt *sd,
for (int repeat = 0; repeat < 2; repeat++) {
for (int i = 0; i < totvert; i++) {
float avg = 0.0f;
+ SculptVertRef vref = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vref, ni) {
avg += dists[ni.index];
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
@@ -555,7 +568,7 @@ static float *sculpt_expand_normal_falloff_create(Sculpt *sd,
* Spherical: Initializes the falloff based on the distance from a vertex, taking symmetry into
* account.
*/
-static float *sculpt_expand_spherical_falloff_create(Object *ob, const int v)
+static float *sculpt_expand_spherical_falloff_create(Object *ob, const SculptVertRef v)
{
SculptSession *ss = ob->sculpt;
const int totvert = SCULPT_vertex_count_get(ss);
@@ -574,7 +587,7 @@ static float *sculpt_expand_spherical_falloff_create(Object *ob, const int v)
if (symm_vertex != -1) {
const float *co = SCULPT_vertex_co_get(ss, symm_vertex);
for (int i = 0; i < totvert; i++) {
- dists[i] = min_ff(dists[i], len_v3v3(co, SCULPT_vertex_co_get(ss, i)));
+ dists[i] = min_ff(dists[i], len_v3v3(co, SCULPT_vertex_co_get(ss, BKE_pbvh_table_index_to_vertex(ss->pbvh, i))));
}
}
}
@@ -587,13 +600,13 @@ static float *sculpt_expand_spherical_falloff_create(Object *ob, const int v)
* boundary to a falloff value of 0. Then, it propagates that falloff to the rest of the mesh so it
* stays parallel to the boundary, increasing the falloff value by 1 on each step.
*/
-static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const int v)
+static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const SculptVertRef v)
{
SculptSession *ss = ob->sculpt;
const int totvert = SCULPT_vertex_count_get(ss);
float *dists = MEM_calloc_arrayN(sizeof(float), totvert, "spherical dist");
BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(totvert, "visited vertices");
- GSQueue *queue = BLI_gsqueue_new(sizeof(int));
+ GSQueue *queue = BLI_gsqueue_new(sizeof(SculptVertRef));
/* Search and initialize a boundary per symmetry pass, then mark those vertices as visited. */
const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
@@ -602,7 +615,7 @@ static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const i
continue;
}
- const int symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass(ob, symm_it, v);
+ const SculptVertRef symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass(ob, symm_it, v);
SculptBoundary *boundary = SCULPT_boundary_data_init(ob, NULL, symm_vertex, FLT_MAX);
if (!boundary) {
@@ -623,7 +636,7 @@ static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const i
/* Propagate the values from the boundaries to the rest of the mesh. */
while (!BLI_gsqueue_is_empty(queue)) {
- int v_next;
+ SculptVertRef v_next;
BLI_gsqueue_pop(queue, &v_next);
SculptVertexNeighborIter ni;
@@ -631,7 +644,10 @@ static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const i
if (BLI_BITMAP_TEST(visited_vertices, ni.index)) {
continue;
}
- dists[ni.index] = dists[v_next] + 1.0f;
+
+ const int v_next_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, v_next);
+
+ dists[ni.index] = dists[v_next_i] + 1.0f;
BLI_BITMAP_ENABLE(visited_vertices, ni.index);
BLI_gsqueue_push(queue, &ni.index);
}
@@ -648,7 +664,7 @@ static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const i
* the base mesh faces when checking a vertex neighbor. For this reason, this is not implement
* using the general flood-fill and sculpt neighbors accessors.
*/
-static float *sculpt_expand_diagonals_falloff_create(Object *ob, const int v)
+static float *sculpt_expand_diagonals_falloff_create(Object *ob, const SculptVertRef v)
{
SculptSession *ss = ob->sculpt;
const int totvert = SCULPT_vertex_count_get(ss);
@@ -663,14 +679,14 @@ static float *sculpt_expand_diagonals_falloff_create(Object *ob, const int v)
/* Search and mask as visited the initial vertices using the enabled symmetry passes. */
BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(totvert, "visited vertices");
- GSQueue *queue = BLI_gsqueue_new(sizeof(int));
+ GSQueue *queue = BLI_gsqueue_new(sizeof(SculptVertRef));
const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
for (char symm_it = 0; symm_it <= symm; symm_it++) {
if (!SCULPT_is_symmetry_iteration_valid(symm_it, symm)) {
continue;
}
- const int symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass(ob, symm_it, v);
+ const SculptVertRef symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass(ob, symm_it, v);
BLI_gsqueue_push(queue, &symm_vertex);
BLI_BITMAP_ENABLE(visited_vertices, symm_vertex);
@@ -683,16 +699,21 @@ static float *sculpt_expand_diagonals_falloff_create(Object *ob, const int v)
/* Propagate the falloff increasing the value by 1 each time a new vertex is visited. */
Mesh *mesh = ob->data;
while (!BLI_gsqueue_is_empty(queue)) {
- int v_next;
+ SculptVertRef v_next;
BLI_gsqueue_pop(queue, &v_next);
- for (int j = 0; j < ss->pmap[v_next].count; j++) {
- MPoly *p = &ss->mpoly[ss->pmap[v_next].indices[j]];
+
+ int v_next_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, v_next);
+
+ for (int j = 0; j < ss->pmap[v_next_i].count; j++) {
+ MPoly *p = &ss->mpoly[ss->pmap[v_next_i].indices[j]];
for (int l = 0; l < p->totloop; l++) {
const int neighbor_v = mesh->mloop[p->loopstart + l].v;
+
if (BLI_BITMAP_TEST(visited_vertices, neighbor_v)) {
continue;
}
- dists[neighbor_v] = dists[v_next] + 1.0f;
+
+ dists[neighbor_v] = dists[v_next_i] + 1.0f;
BLI_BITMAP_ENABLE(visited_vertices, neighbor_v);
BLI_gsqueue_push(queue, &neighbor_v);
}
@@ -937,10 +958,12 @@ static void sculpt_expand_initialize_from_face_set_boundary(Object *ob,
BLI_bitmap *enabled_vertices = BLI_BITMAP_NEW(totvert, "enabled vertices");
for (int i = 0; i < totvert; i++) {
- if (!SCULPT_vertex_has_unique_face_set(ss, i)) {
+ SculptVertRef vref = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
+ if (!SCULPT_vertex_has_unique_face_set(ss, vref)) {
continue;
}
- if (!SCULPT_vertex_has_face_set(ss, i, active_face_set)) {
+ if (!SCULPT_vertex_has_face_set(ss, vref, active_face_set)) {
continue;
}
BLI_BITMAP_ENABLE(enabled_vertices, i);
@@ -957,8 +980,10 @@ static void sculpt_expand_initialize_from_face_set_boundary(Object *ob,
if (internal_falloff) {
for (int i = 0; i < totvert; i++) {
- if (!(SCULPT_vertex_has_face_set(ss, i, active_face_set) &&
- SCULPT_vertex_has_unique_face_set(ss, i))) {
+ SculptVertRef vref = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
+ if (!(SCULPT_vertex_has_face_set(ss, vref, active_face_set) &&
+ SCULPT_vertex_has_unique_face_set(ss, vref))) {
continue;
}
expand_cache->vert_falloff[i] *= -1.0f;
@@ -976,7 +1001,9 @@ static void sculpt_expand_initialize_from_face_set_boundary(Object *ob,
}
else {
for (int i = 0; i < totvert; i++) {
- if (!SCULPT_vertex_has_face_set(ss, i, active_face_set)) {
+ SculptVertRef vref = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
+ if (!SCULPT_vertex_has_face_set(ss, vref, active_face_set)) {
continue;
}
expand_cache->vert_falloff[i] = 0.0f;
@@ -1406,14 +1433,16 @@ static void sculpt_expand_face_sets_restore(SculptSession *ss, ExpandCache *expa
}
}
-static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const int vertex)
+static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const SculptVertRef vertex)
{
SculptSession *ss = ob->sculpt;
+ const int vertex_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, vertex);
+
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
ExpandCache *expand_cache = ss->expand_cache;
/* Update the active factor in the cache. */
- if (vertex == SCULPT_EXPAND_VERTEX_NONE) {
+ if (vertex.i == SCULPT_EXPAND_VERTEX_NONE) {
/* This means that the cursor is not over the mesh, so a valid active falloff can't be
* determined. In this situations, don't evaluate enabled states and default all vertices in
* connected components to enabled. */
@@ -1421,7 +1450,7 @@ static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const int v
expand_cache->all_enabled = true;
}
else {
- expand_cache->active_falloff = expand_cache->vert_falloff[vertex];
+ expand_cache->active_falloff = expand_cache->vert_falloff[vertex_i];
expand_cache->all_enabled = false;
}
@@ -1462,7 +1491,7 @@ static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const int v
* Updates the #SculptSession cursor data and gets the active vertex
* if the cursor is over the mesh.
*/
-static int sculpt_expand_target_vertex_update_and_get(bContext *C,
+static SculptVertRef sculpt_expand_target_vertex_update_and_get(bContext *C,
Object *ob,
const float mouse[2])
{
@@ -1471,7 +1500,9 @@ static int sculpt_expand_target_vertex_update_and_get(bContext *C,
if (SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false)) {
return SCULPT_active_vertex_get(ss);
}
- return SCULPT_EXPAND_VERTEX_NONE;
+
+ SculptVertRef ret = {SCULPT_EXPAND_VERTEX_NONE};
+ return ret;
}
/**
@@ -1572,7 +1603,7 @@ static void sculpt_expand_finish(bContext *C)
*/
static void sculpt_expand_find_active_connected_components_from_vert(Object *ob,
ExpandCache *expand_cache,
- const int initial_vertex)
+ const SculptVertRef initial_vertex)
{
SculptSession *ss = ob->sculpt;
for (int i = 0; i < EXPAND_SYMM_AREAS; i++) {
@@ -1585,11 +1616,12 @@ static void sculpt_expand_find_active_connected_components_from_vert(Object *ob,
continue;
}
- const int symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass(
+ const SculptVertRef symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass(
ob, symm_it, initial_vertex);
+ const int symm_vertex_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, symm_vertex);
expand_cache->active_connected_components[(int)symm_it] =
- ss->vertex_info.connected_component[symm_vertex];
+ ss->vertex_info.connected_component[symm_vertex_i];
}
}
@@ -1603,8 +1635,9 @@ static void sculpt_expand_set_initial_components_for_mouse(bContext *C,
const float mouse[2])
{
SculptSession *ss = ob->sculpt;
- int initial_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mouse);
- if (initial_vertex == SCULPT_EXPAND_VERTEX_NONE) {
+ SculptVertRef initial_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mouse);
+
+ if (initial_vertex.i == SCULPT_EXPAND_VERTEX_NONE) {
/* Cursor not over the mesh, for creating valid initial falloffs, fallback to the last active
* vertex in the sculpt session. */
initial_vertex = SCULPT_active_vertex_get(ss);
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c
index df03d2adeaf..7356b0ba071 100644
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.c
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c
@@ -23,6 +23,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_array.h"
#include "BLI_blenlib.h"
#include "BLI_hash.h"
#include "BLI_math.h"
@@ -135,6 +136,7 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
+ const int active_fset = abs(ss->cache->paint_face_set);
MVert *mvert = SCULPT_mesh_deformed_mverts_get(ss);
@@ -158,7 +160,7 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
if (fade > 0.05f && ss->face_sets[vert_map->indices[j]] > 0) {
@@ -166,7 +168,34 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
}
}
}
+ else if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ BMVert *v = vd.bm_vert;
+ BMIter iter;
+ BMFace *f;
+ BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
+ float poly_center[3];
+ BM_face_calc_center_median(f, poly_center);
+
+ if (sculpt_brush_test_sq_fn(&test, poly_center)) {
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.vertex,
+ thread_id);
+
+ int fset = BM_ELEM_CD_GET_INT(f, ss->cd_faceset_offset);
+
+ if (fade > 0.05f && fset > 0) {
+ BM_ELEM_CD_SET_INT(f, ss->cd_faceset_offset, active_fset);
+ }
+ }
+ }
+ }
else if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
{
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
@@ -179,11 +208,11 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
if (fade > 0.05f) {
- SCULPT_vertex_face_set_set(ss, vd.index, ss->cache->paint_face_set);
+ SCULPT_vertex_face_set_set(ss, vd.vertex, ss->cache->paint_face_set);
}
}
}
@@ -219,7 +248,7 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
- if (relax_face_sets == SCULPT_vertex_has_unique_face_set(ss, vd.index)) {
+ if (relax_face_sets == SCULPT_vertex_has_unique_face_set(ss, vd.vertex)) {
continue;
}
@@ -230,7 +259,7 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
SCULPT_relax_vertex(ss, &vd, fade * bstrength, relax_face_sets, vd.co);
@@ -344,8 +373,11 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
if (mode == SCULPT_FACE_SET_MASKED) {
for (int i = 0; i < tot_vert; i++) {
- if (SCULPT_vertex_mask_get(ss, i) >= threshold && SCULPT_vertex_visible_get(ss, i)) {
- SCULPT_vertex_face_set_set(ss, i, next_face_set);
+ SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
+ if (SCULPT_vertex_mask_get(ss, vertex) >= threshold &&
+ SCULPT_vertex_visible_get(ss, vertex)) {
+ SCULPT_vertex_face_set_set(ss, vertex, next_face_set);
}
}
}
@@ -357,7 +389,9 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
* sets and the performance hit of rendering the overlay. */
bool all_visible = true;
for (int i = 0; i < tot_vert; i++) {
- if (!SCULPT_vertex_visible_get(ss, i)) {
+ SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
+ if (!SCULPT_vertex_visible_get(ss, vertex)) {
all_visible = false;
break;
}
@@ -371,15 +405,19 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
}
for (int i = 0; i < tot_vert; i++) {
- if (SCULPT_vertex_visible_get(ss, i)) {
- SCULPT_vertex_face_set_set(ss, i, next_face_set);
+ SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
+ if (SCULPT_vertex_visible_get(ss, vertex)) {
+ SCULPT_vertex_face_set_set(ss, vertex, next_face_set);
}
}
}
if (mode == SCULPT_FACE_SET_ALL) {
for (int i = 0; i < tot_vert; i++) {
- SCULPT_vertex_face_set_set(ss, i, next_face_set);
+ SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
+ SCULPT_vertex_face_set_set(ss, vertex, next_face_set);
}
}
@@ -392,7 +430,8 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
.use_toolflags = true,
}));
- BM_mesh_bm_from_me(bm,
+ BM_mesh_bm_from_me(NULL,
+ bm,
mesh,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
@@ -570,7 +609,8 @@ static void sculpt_face_sets_init_flood_fill(Object *ob,
.use_toolflags = true,
}));
- BM_mesh_bm_from_me(bm,
+ BM_mesh_bm_from_me(NULL,
+ bm,
mesh,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
@@ -648,7 +688,8 @@ static void sculpt_face_sets_init_loop(Object *ob, const int mode)
.use_toolflags = true,
}));
- BM_mesh_bm_from_me(bm,
+ BM_mesh_bm_from_me(NULL,
+ bm,
mesh,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
@@ -865,7 +906,9 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op)
* be synced from face sets to non-manifold vertices. */
if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
for (int i = 0; i < tot_vert; i++) {
- if (!SCULPT_vertex_visible_get(ss, i)) {
+ SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
+ if (!SCULPT_vertex_visible_get(ss, vertex)) {
hidden_vertex = true;
break;
}
@@ -1080,12 +1123,60 @@ static EnumPropertyItem prop_sculpt_face_sets_edit_types[] = {
{0, NULL, 0, NULL, NULL},
};
+static void sculpt_face_set_grow_bmesh(Object *ob,
+ SculptSession *ss,
+ const int *prev_face_sets,
+ const int active_face_set_id,
+ const bool modify_hidden)
+{
+ BMesh *bm = ss->bm;
+ BMIter iter;
+ BMFace *f;
+ BMFace **faces = NULL;
+ BLI_array_declare(faces);
+
+ if (ss->cd_faceset_offset < 0) {
+ return;
+ }
+
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, BM_ELEM_HIDDEN) && !modify_hidden) {
+ continue;
+ }
+
+ int fset = abs(BM_ELEM_CD_GET_INT(f, ss->cd_faceset_offset));
+
+ if (fset == active_face_set_id) {
+ BLI_array_append(faces, f);
+ }
+ }
+
+ for (int i = 0; i < BLI_array_len(faces); i++) {
+ BMFace *f = faces[i];
+ BMLoop *l = f->l_first;
+
+ do {
+ if (l->radial_next != l) {
+ BM_ELEM_CD_GET_INT(l->radial_next->f, active_face_set_id);
+ }
+ l = l->next;
+ } while (l != f->l_first);
+ }
+
+ BLI_array_free(faces);
+}
+
static void sculpt_face_set_grow(Object *ob,
SculptSession *ss,
const int *prev_face_sets,
const int active_face_set_id,
const bool modify_hidden)
{
+ if (ss && ss->bm) {
+ sculpt_face_set_grow_bmesh(ob, ss, prev_face_sets, active_face_set_id, modify_hidden);
+ return;
+ }
+
Mesh *mesh = BKE_mesh_from_object(ob);
for (int p = 0; p < mesh->totpoly; p++) {
if (!modify_hidden && prev_face_sets[p] <= 0) {
@@ -1114,6 +1205,11 @@ static void sculpt_face_set_shrink(Object *ob,
const int active_face_set_id,
const bool modify_hidden)
{
+ if (ss && ss->bm) {
+ // XXX implement me
+ return;
+ }
+
Mesh *mesh = BKE_mesh_from_object(ob);
for (int p = 0; p < mesh->totpoly; p++) {
if (!modify_hidden && prev_face_sets[p] <= 0) {
@@ -1180,7 +1276,8 @@ static void sculpt_face_set_delete_geometry(Object *ob,
.use_toolflags = true,
}));
- BM_mesh_bm_from_me(bm,
+ BM_mesh_bm_from_me(ob,
+ bm,
mesh,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
@@ -1201,6 +1298,7 @@ static void sculpt_face_set_delete_geometry(Object *ob,
BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
BM_mesh_bm_to_me(NULL,
+ ob,
bm,
ob->data,
(&(struct BMeshToMeshParams){
@@ -1215,17 +1313,21 @@ static void sculpt_face_set_edit_fair_face_set(Object *ob,
const int fair_order)
{
SculptSession *ss = ob->sculpt;
+
const int totvert = SCULPT_vertex_count_get(ss);
Mesh *mesh = ob->data;
bool *fair_vertices = MEM_malloc_arrayN(sizeof(bool), totvert, "fair vertices");
+ SCULPT_vertex_random_access_ensure(ss);
SCULPT_boundary_info_ensure(ob);
for (int i = 0; i < totvert; i++) {
- fair_vertices[i] = !SCULPT_vertex_is_boundary(ss, i) &&
- SCULPT_vertex_has_face_set(ss, i, active_face_set_id) &&
- SCULPT_vertex_has_unique_face_set(ss, i);
+ SculptVertRef vref = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
+ fair_vertices[i] = !SCULPT_vertex_is_boundary(ss, vref) &&
+ SCULPT_vertex_has_face_set(ss, vref, active_face_set_id) &&
+ SCULPT_vertex_has_unique_face_set(ss, vref);
}
MVert *mvert = SCULPT_mesh_deformed_mverts_get(ss);
@@ -1242,13 +1344,13 @@ static void sculpt_face_set_apply_edit(Object *ob,
switch (mode) {
case SCULPT_FACE_SET_EDIT_GROW: {
- int *prev_face_sets = MEM_dupallocN(ss->face_sets);
+ int *prev_face_sets = ss->face_sets ? MEM_dupallocN(ss->face_sets) : NULL;
sculpt_face_set_grow(ob, ss, prev_face_sets, active_face_set_id, modify_hidden);
MEM_SAFE_FREE(prev_face_sets);
break;
}
case SCULPT_FACE_SET_EDIT_SHRINK: {
- int *prev_face_sets = MEM_dupallocN(ss->face_sets);
+ int *prev_face_sets = ss->face_sets ? MEM_dupallocN(ss->face_sets) : NULL;
sculpt_face_set_shrink(ob, ss, prev_face_sets, active_face_set_id, modify_hidden);
MEM_SAFE_FREE(prev_face_sets);
break;
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
index b5fade32a25..6f1fcfd8ea5 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
@@ -107,7 +107,7 @@ static void color_filter_task_cb(void *__restrict userdata,
const int mode = data->filter_type;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COLOR);
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
@@ -119,7 +119,7 @@ static void color_filter_task_cb(void *__restrict userdata,
float fade = vd.mask ? *vd.mask : 0.0f;
fade = 1.0f - fade;
fade *= data->filter_strength;
- fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.index);
+ fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex);
if (fade == 0.0f) {
continue;
}
@@ -197,7 +197,7 @@ static void color_filter_task_cb(void *__restrict userdata,
case COLOR_FILTER_SMOOTH: {
fade = clamp_f(fade, -1.0f, 1.0f);
float smooth_color[4];
- SCULPT_neighbor_color_average(ss, smooth_color, vd.index);
+ SCULPT_neighbor_color_average(ss, smooth_color, vd.vertex);
blend_color_interpolate_float(final_color, vd.col, smooth_color, fade);
break;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
index 0297ed73dd4..5ce5a862cbe 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
@@ -120,7 +120,7 @@ static void mask_filter_task_cb(void *__restrict userdata,
switch (mode) {
case MASK_FILTER_SMOOTH:
case MASK_FILTER_SHARPEN: {
- float val = SCULPT_neighbor_mask_average(ss, vd.index);
+ float val = SCULPT_neighbor_mask_average(ss, vd.vertex);
val -= *vd.mask;
@@ -140,7 +140,7 @@ static void mask_filter_task_cb(void *__restrict userdata,
}
case MASK_FILTER_GROW:
max = 0.0f;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
float vmask_f = data->prev_mask[ni.index];
if (vmask_f > max) {
max = vmask_f;
@@ -151,7 +151,7 @@ static void mask_filter_task_cb(void *__restrict userdata,
break;
case MASK_FILTER_SHRINK:
min = 1.0f;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
float vmask_f = data->prev_mask[ni.index];
if (vmask_f < min) {
min = vmask_f;
@@ -233,7 +233,9 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
if (ELEM(filter_type, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) {
prev_mask = MEM_mallocN(num_verts * sizeof(float), "prevmask");
for (int j = 0; j < num_verts; j++) {
- prev_mask[j] = SCULPT_vertex_mask_get(ss, j);
+ SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, j);
+
+ prev_mask[j] = SCULPT_vertex_mask_get(ss, vertex);
}
}
@@ -324,9 +326,9 @@ static float neighbor_dirty_mask(SculptSession *ss, PBVHVertexIter *vd)
zero_v3(avg);
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->index, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->vertex, ni) {
float normalized[3];
- sub_v3_v3v3(normalized, SCULPT_vertex_co_get(ss, ni.index), vd->co);
+ sub_v3_v3v3(normalized, SCULPT_vertex_co_get(ss, ni.vertex), vd->co);
normalize_v3(normalized);
add_v3_v3(avg, normalized);
total++;
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
index 3cf6a8cc561..d7c8a93f1ab 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
@@ -293,7 +293,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
const eSculptMeshFilterType filter_type = data->filter_type;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i], SCULPT_UNDO_COORDS);
/* When using the relax face sets meshes filter,
* each 3 iterations, do a whole mesh relax to smooth the contents of the Face Set. */
@@ -309,7 +309,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
float fade = vd.mask ? *vd.mask : 0.0f;
fade = 1.0f - fade;
fade *= data->filter_strength;
- fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.index);
+ fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex);
if (fade == 0.0f && filter_type != MESH_FILTER_SURFACE_SMOOTH) {
/* Surface Smooth can't skip the loop for this vertex as it needs to calculate its
@@ -327,7 +327,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
}
if (filter_type == MESH_FILTER_RELAX_FACE_SETS) {
- if (relax_face_sets == SCULPT_vertex_has_unique_face_set(ss, vd.index)) {
+ if (relax_face_sets == SCULPT_vertex_has_unique_face_set(ss, vd.vertex)) {
continue;
}
}
@@ -335,7 +335,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
switch (filter_type) {
case MESH_FILTER_SMOOTH:
fade = clamp_f(fade, -1.0f, 1.0f);
- SCULPT_neighbor_coords_average_interior(ss, avg, vd.index);
+ SCULPT_neighbor_coords_average_interior(ss, avg, vd.vertex);
sub_v3_v3v3(val, avg, orig_co);
madd_v3_v3v3fl(val, orig_co, val, fade);
sub_v3_v3v3(disp, val, orig_co);
@@ -398,7 +398,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
disp,
vd.co,
ss->filter_cache->surface_smooth_laplacian_disp,
- vd.index,
+ vd.vertex,
orig_data.co,
ss->filter_cache->surface_smooth_shape_preservation);
break;
@@ -412,10 +412,10 @@ static void mesh_filter_task_cb(void *__restrict userdata,
float disp_sharpen[3] = {0.0f, 0.0f, 0.0f};
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
float disp_n[3];
sub_v3_v3v3(
- disp_n, SCULPT_vertex_co_get(ss, ni.index), SCULPT_vertex_co_get(ss, vd.index));
+ disp_n, SCULPT_vertex_co_get(ss, ni.vertex), SCULPT_vertex_co_get(ss, vd.vertex));
mul_v3_fl(disp_n, ss->filter_cache->sharpen_factor[ni.index]);
add_v3_v3(disp_sharpen, disp_n);
}
@@ -425,7 +425,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
float disp_avg[3];
float avg_co[3];
- SCULPT_neighbor_coords_average(ss, avg_co, vd.index);
+ SCULPT_neighbor_coords_average(ss, avg_co, vd.vertex);
sub_v3_v3v3(disp_avg, avg_co, vd.co);
mul_v3_v3fl(
disp_avg, disp_avg, smooth_ratio * pow2f(ss->filter_cache->sharpen_factor[vd.index]));
@@ -487,9 +487,11 @@ static void mesh_filter_enhance_details_init_directions(SculptSession *ss)
filter_cache->detail_directions = MEM_malloc_arrayN(
totvert, sizeof(float[3]), "detail directions");
for (int i = 0; i < totvert; i++) {
+ SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
float avg[3];
- SCULPT_neighbor_coords_average(ss, avg, i);
- sub_v3_v3v3(filter_cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, i));
+ SCULPT_neighbor_coords_average(ss, avg, vertex);
+ sub_v3_v3v3(filter_cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, vertex));
}
}
@@ -513,8 +515,10 @@ static void mesh_filter_init_limit_surface_co(SculptSession *ss)
filter_cache->limit_surface_co = MEM_malloc_arrayN(
sizeof(float[3]), totvert, "limit surface co");
+
for (int i = 0; i < totvert; i++) {
- SCULPT_vertex_limit_surface_get(ss, i, filter_cache->limit_surface_co[i]);
+ SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+ SCULPT_vertex_limit_surface_get(ss, vertex, filter_cache->limit_surface_co[i]);
}
}
@@ -535,8 +539,10 @@ static void mesh_filter_sharpen_init(SculptSession *ss,
for (int i = 0; i < totvert; i++) {
float avg[3];
- SCULPT_neighbor_coords_average(ss, avg, i);
- sub_v3_v3v3(filter_cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, i));
+ SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
+ SCULPT_neighbor_coords_average(ss, avg, vertex);
+ sub_v3_v3v3(filter_cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, vertex));
filter_cache->sharpen_factor[i] = len_v3(filter_cache->detail_directions[i]);
}
@@ -559,11 +565,12 @@ static void mesh_filter_sharpen_init(SculptSession *ss,
smooth_iterations++) {
for (int i = 0; i < totvert; i++) {
float direction_avg[3] = {0.0f, 0.0f, 0.0f};
+ SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
float sharpen_avg = 0;
int total = 0;
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
add_v3_v3(direction_avg, filter_cache->detail_directions[ni.index]);
sharpen_avg += filter_cache->sharpen_factor[ni.index];
total++;
@@ -591,7 +598,7 @@ static void mesh_filter_surface_smooth_displace_task_cb(
float fade = vd.mask ? *vd.mask : 0.0f;
fade = 1.0f - fade;
fade *= data->filter_strength;
- fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.index);
+ fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex);
if (fade == 0.0f) {
continue;
}
@@ -599,7 +606,7 @@ static void mesh_filter_surface_smooth_displace_task_cb(
SCULPT_surface_smooth_displace_step(ss,
vd.co,
ss->filter_cache->surface_smooth_laplacian_disp,
- vd.index,
+ vd.vertex,
ss->filter_cache->surface_smooth_current_vertex,
clamp_f(fade, 0.0f, 1.0f));
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 19c4eda7593..6ec6f923a1d 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -51,6 +51,7 @@ bool SCULPT_poll(struct bContext *C);
bool SCULPT_poll_view3d(struct bContext *C);
bool SCULPT_vertex_colors_poll(struct bContext *C);
+bool SCULPT_vertex_colors_poll_no_bmesh(struct bContext *C);
/* Updates */
@@ -98,20 +99,20 @@ char SCULPT_mesh_symmetry_xyz_get(Object *object);
void SCULPT_vertex_random_access_ensure(struct SculptSession *ss);
int SCULPT_vertex_count_get(struct SculptSession *ss);
-const float *SCULPT_vertex_co_get(struct SculptSession *ss, int index);
-void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3]);
-float SCULPT_vertex_mask_get(struct SculptSession *ss, int index);
-const float *SCULPT_vertex_color_get(SculptSession *ss, int index);
+const float *SCULPT_vertex_co_get(struct SculptSession *ss, SculptVertRef index);
+void SCULPT_vertex_normal_get(SculptSession *ss, SculptVertRef index, float no[3]);
+float SCULPT_vertex_mask_get(struct SculptSession *ss, SculptVertRef index);
+const float *SCULPT_vertex_color_get(SculptSession *ss, SculptVertRef index);
-const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, int index);
-void SCULPT_vertex_persistent_normal_get(SculptSession *ss, int index, float no[3]);
+const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, SculptVertRef index);
+void SCULPT_vertex_persistent_normal_get(SculptSession *ss, SculptVertRef index, float no[3]);
/* Coordinates used for manipulating the base mesh when Grab Active Vertex is enabled. */
-const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, int index);
+const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, SculptVertRef index);
/* Returns the info of the limit surface when Multires is available, otherwise it returns the
* current coordinate of the vertex. */
-void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3]);
+void SCULPT_vertex_limit_surface_get(SculptSession *ss, SculptVertRef index, float r_co[3]);
/* Returns the pointer to the coordinates that should be edited from a brush tool iterator
* depending on the given deformation target. */
@@ -122,22 +123,26 @@ float *SCULPT_brush_deform_target_vertex_co_get(SculptSession *ss,
#define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256
typedef struct SculptVertexNeighborIter {
/* Storage */
- int *neighbors;
+ SculptVertRef *neighbors;
+ int *neighbor_indices;
+
int size;
int capacity;
- int neighbors_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY];
+ SculptVertRef neighbors_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY];
+ int neighbor_indices_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY];
/* Internal iterator. */
int num_duplicates;
int i;
/* Public */
+ SculptVertRef vertex;
int index;
bool is_duplicate;
} SculptVertexNeighborIter;
void SCULPT_vertex_neighbors_get(struct SculptSession *ss,
- const int index,
+ const SculptVertRef vref,
const bool include_duplicates,
SculptVertexNeighborIter *iter);
@@ -146,7 +151,8 @@ void SCULPT_vertex_neighbors_get(struct SculptSession *ss,
SCULPT_vertex_neighbors_get(ss, v_index, false, &neighbor_iterator); \
for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \
neighbor_iterator.i++) { \
- neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i];
+ neighbor_iterator.vertex = neighbor_iterator.neighbors[neighbor_iterator.i]; \
+ neighbor_iterator.index = neighbor_iterator.neighbor_indices[neighbor_iterator.i];
/* Iterate over neighboring and duplicate vertices (for PBVH_GRIDS). Duplicates come
* first since they are nearest for floodfill. */
@@ -154,7 +160,8 @@ void SCULPT_vertex_neighbors_get(struct SculptSession *ss,
SCULPT_vertex_neighbors_get(ss, v_index, true, &neighbor_iterator); \
for (neighbor_iterator.i = neighbor_iterator.size - 1; neighbor_iterator.i >= 0; \
neighbor_iterator.i--) { \
- neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i]; \
+ neighbor_iterator.vertex = neighbor_iterator.neighbors[neighbor_iterator.i]; \
+ neighbor_iterator.index = neighbor_iterator.neighbor_indices[neighbor_iterator.i]; \
neighbor_iterator.is_duplicate = (neighbor_iterator.i >= \
neighbor_iterator.size - neighbor_iterator.num_duplicates);
@@ -165,7 +172,7 @@ void SCULPT_vertex_neighbors_get(struct SculptSession *ss,
} \
((void)0)
-int SCULPT_active_vertex_get(SculptSession *ss);
+SculptVertRef SCULPT_active_vertex_get(SculptSession *ss);
const float *SCULPT_active_vertex_co_get(SculptSession *ss);
void SCULPT_active_vertex_normal_get(SculptSession *ss, float normal[3]);
@@ -185,14 +192,14 @@ void SCULPT_fake_neighbors_free(struct Object *ob);
/* Vertex Info. */
void SCULPT_boundary_info_ensure(Object *object);
/* Boundary Info needs to be initialized in order to use this function. */
-bool SCULPT_vertex_is_boundary(const SculptSession *ss, const int index);
+bool SCULPT_vertex_is_boundary(const SculptSession *ss, const SculptVertRef index);
void SCULPT_connected_components_ensure(Object *ob);
/* Sculpt Visibility API */
-void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible);
-bool SCULPT_vertex_visible_get(SculptSession *ss, int index);
+void SCULPT_vertex_visible_set(SculptSession *ss, SculptVertRef index, bool visible);
+bool SCULPT_vertex_visible_get(SculptSession *ss, SculptVertRef index);
void SCULPT_visibility_sync_all_face_sets_to_vertices(struct Object *ob);
void SCULPT_visibility_sync_all_vertex_to_face_sets(struct SculptSession *ss);
@@ -200,17 +207,17 @@ void SCULPT_visibility_sync_all_vertex_to_face_sets(struct SculptSession *ss);
/* Face Sets API */
int SCULPT_active_face_set_get(SculptSession *ss);
-int SCULPT_vertex_face_set_get(SculptSession *ss, int index);
-void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set);
+int SCULPT_vertex_face_set_get(SculptSession *ss, SculptVertRef index);
+void SCULPT_vertex_face_set_set(SculptSession *ss, SculptVertRef index, int face_set);
-bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set);
-bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index);
+bool SCULPT_vertex_has_face_set(SculptSession *ss, SculptVertRef index, int face_set);
+bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, SculptVertRef index);
int SCULPT_face_set_next_available_get(SculptSession *ss);
void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visible);
-bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index);
-bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index);
+bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, SculptVertRef index);
+bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, SculptVertRef index);
void SCULPT_face_sets_visibility_invert(SculptSession *ss);
void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible);
@@ -224,24 +231,22 @@ typedef struct {
struct BMLog *bm_log;
struct SculptUndoNode *unode;
+ int datatype;
float (*coords)[3];
short (*normals)[3];
const float *vmasks;
float (*colors)[4];
+ short _no[3];
/* Original coordinate, normal, and mask. */
const float *co;
const short *no;
float mask;
const float *col;
+ struct PBVH *pbvh;
+ struct SculptSession *ss;
} SculptOrigVertData;
-void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *node);
-void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter *iter);
-void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data,
- Object *ob,
- struct SculptUndoNode *unode);
-
/* Utils. */
void SCULPT_calc_brush_plane(struct Sculpt *sd,
struct Object *ob,
@@ -253,11 +258,11 @@ void SCULPT_calc_brush_plane(struct Sculpt *sd,
void SCULPT_calc_area_normal(
Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3]);
-int SCULPT_nearest_vertex_get(struct Sculpt *sd,
- struct Object *ob,
- const float co[3],
- float max_distance,
- bool use_original);
+SculptVertRef SCULPT_nearest_vertex_get(struct Sculpt *sd,
+ struct Object *ob,
+ const float co[3],
+ float max_distance,
+ bool use_original);
int SCULPT_plane_point_side(const float co[3], const float plane[4]);
int SCULPT_plane_trim(const struct StrokeCache *cache,
@@ -299,14 +304,15 @@ void SCULPT_floodfill_add_initial_with_symmetry(struct Sculpt *sd,
struct Object *ob,
struct SculptSession *ss,
SculptFloodFill *flood,
- int index,
+ SculptVertRef index,
float radius);
-void SCULPT_floodfill_add_initial(SculptFloodFill *flood, int index);
+
+void SCULPT_floodfill_add_initial(SculptFloodFill *flood, SculptVertRef index);
void SCULPT_floodfill_add_and_skip_initial(SculptFloodFill *flood, int index);
void SCULPT_floodfill_execute(
struct SculptSession *ss,
SculptFloodFill *flood,
- bool (*func)(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata),
+ bool (*func)(SculptSession *ss, SculptVertRef from_v, SculptVertRef to_v, bool is_duplicate, void *userdata),
void *userdata);
void SCULPT_floodfill_free(SculptFloodFill *flood);
@@ -319,6 +325,11 @@ enum eDynTopoWarnFlag {
DYNTOPO_WARN_MODIFIER = (1 << 3),
};
+struct Mesh;
+
+void SCULPT_dyntopo_node_layers_update_offsets(SculptSession *ss);
+void SCULPT_dynamic_topology_sync_layers(Object *ob, struct Mesh *me);
+
void SCULPT_dynamic_topology_enable_ex(struct Main *bmain,
struct Depsgraph *depsgraph,
Scene *scene,
@@ -341,7 +352,7 @@ void SCULPT_pbvh_clear(Object *ob);
/* Auto-masking. */
float SCULPT_automasking_factor_get(struct AutomaskingCache *automasking,
SculptSession *ss,
- int vert);
+ SculptVertRef vert);
/* Returns the automasking cache depending on the active tool. Used for code that can run both for
* brushes and filter. */
@@ -515,7 +526,7 @@ void SCULPT_pose_ik_chain_free(struct SculptPoseIKChain *ik_chain);
/* Boundary Brush. */
struct SculptBoundary *SCULPT_boundary_data_init(Object *object,
Brush *brush,
- const int initial_vertex,
+ const SculptVertRef initial_vertex,
const float radius);
void SCULPT_boundary_data_free(struct SculptBoundary *boundary);
void SCULPT_do_boundary_brush(struct Sculpt *sd,
@@ -548,12 +559,17 @@ void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
/* Smooth Brush. */
void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], struct BMVert *v);
-void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int index);
-float SCULPT_neighbor_mask_average(SculptSession *ss, int index);
-void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index);
+void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], SculptVertRef index);
+float SCULPT_neighbor_mask_average(SculptSession *ss, SculptVertRef index);
+void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], SculptVertRef index);
/* Mask the mesh boundaries smoothing only the mesh surface without using automasking. */
-void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3], int index);
+void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
+ float result[3],
+ SculptVertRef index);
+
+void SCULPT_smooth_vcol_boundary(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, float bstrength);
void SCULPT_smooth(Sculpt *sd,
Object *ob,
@@ -569,13 +585,13 @@ void SCULPT_surface_smooth_laplacian_step(SculptSession *ss,
float *disp,
const float co[3],
float (*laplacian_disp)[3],
- const int v_index,
+ const SculptVertRef v_index,
const float origco[3],
const float alpha);
void SCULPT_surface_smooth_displace_step(SculptSession *ss,
float *co,
float (*laplacian_disp)[3],
- const int v_index,
+ const SculptVertRef v_index,
const float beta,
const float fade);
void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
@@ -634,8 +650,8 @@ typedef struct SculptUndoNode {
int totvert;
/* non-multires */
- int maxvert; /* to verify if totvert it still the same */
- int *index; /* to restore into right location */
+ int maxvert; /* to verify if totvert it still the same */
+ SculptVertRef *index; /* to restore into right location */
BLI_bitmap *vert_hidden;
/* multires */
@@ -672,7 +688,11 @@ typedef struct SculptUndoNode {
/* Sculpt Face Sets */
int *face_sets;
+ bool *nodemap;
+ int nodemap_size;
+
size_t undo_size;
+ //int gen, lasthash;
} SculptUndoNode;
/* Factor of brush to have rake point following behind
@@ -786,7 +806,7 @@ typedef struct SculptThreadedTaskData {
bool mask_by_color_preserve_mask;
/* Index of the vertex that is going to be used as a reference for the colors. */
- int mask_by_color_vertex;
+ SculptVertRef mask_by_color_vertex;
float *mask_by_color_floodfill;
int face_set;
@@ -827,6 +847,8 @@ typedef struct {
bool original;
/* This ignores fully masked and fully hidden nodes. */
bool ignore_fully_ineffective;
+ struct Object *ob;
+ struct Brush *brush;
} SculptSearchSphereData;
typedef struct {
@@ -863,7 +885,7 @@ float SCULPT_brush_strength_factor(struct SculptSession *ss,
const short vno[3],
const float fno[3],
const float mask,
- const int vertex_index,
+ const SculptVertRef vertex_index,
const int thread_id);
/* Tilts a normal by the x and y tilt values using the view axis. */
@@ -894,6 +916,7 @@ typedef struct AutomaskingSettings {
/* Flags from eAutomasking_flag. */
int flags;
int initial_face_set;
+ float concave_factor;
} AutomaskingSettings;
typedef struct AutomaskingCache {
@@ -1138,7 +1161,7 @@ typedef struct ExpandCache {
* during the execution of Expand by moving the origin. */
float initial_mouse_move[2];
float initial_mouse[2];
- int initial_active_vertex;
+ SculptVertRef initial_active_vertex;
int initial_active_face_set;
/* Maximum number of vertices allowed in the SculptSession for previewing the falloff using
@@ -1299,8 +1322,17 @@ void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache,
const float angle);
void SCULPT_cache_free(StrokeCache *cache);
+void SCULPT_orig_vert_data_init(SculptOrigVertData *data,
+ Object *ob,
+ PBVHNode *node,
+ SculptUndoType type);
+void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter *iter);
+void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data,
+ Object *ob,
+ struct SculptUndoNode *unode);
+
SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType type);
-SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node);
+SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node, SculptUndoType type);
SculptUndoNode *SCULPT_undo_get_first_node(void);
void SCULPT_undo_push_begin(struct Object *ob, const char *name);
void SCULPT_undo_push_end(void);
@@ -1363,3 +1395,21 @@ void SCULPT_OT_set_detail_size(struct wmOperatorType *ot);
/* Dyntopo. */
void SCULPT_OT_dynamic_topology_toggle(struct wmOperatorType *ot);
+bool SCULPT_ensure_dyntopo_node_undo(struct Object *ob,
+ struct PBVHNode *node,
+ SculptUndoType type,
+ int extraType);
+
+void SCULPT_update_flat_vcol_shading(struct Object *ob, struct Scene *scene);
+float SCULPT_calc_concavity(SculptSession *ss, SculptVertRef vref);
+
+
+typedef struct SculptCurvatureData {
+ float ks[3];
+ float principle[3][3]; // normalized
+} SculptCurvatureData;
+
+bool SCULPT_calc_principle_curvatures(SculptSession *ss,
+ SculptVertRef vertex,
+ SculptCurvatureData *out);
+
diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
index 5e229e020ad..e453ae49e65 100644
--- a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
+++ b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
@@ -119,7 +119,7 @@ static void sculpt_expand_task_cb(void *__restrict userdata,
int vi = vd.index;
float final_mask = *vd.mask;
if (data->mask_expand_use_normals) {
- if (ss->filter_cache->normal_factor[SCULPT_active_vertex_get(ss)] <
+ if (ss->filter_cache->normal_factor[BKE_pbvh_vertex_index_to_table(ss->pbvh, SCULPT_active_vertex_get(ss))] <
ss->filter_cache->normal_factor[vd.index]) {
final_mask = 1.0f;
}
@@ -139,7 +139,7 @@ static void sculpt_expand_task_cb(void *__restrict userdata,
if (data->mask_expand_create_face_set) {
if (final_mask == 1.0f) {
- SCULPT_vertex_face_set_set(ss, vd.index, ss->filter_cache->new_face_set);
+ SCULPT_vertex_face_set_set(ss, vd.vertex, ss->filter_cache->new_face_set);
}
BKE_pbvh_node_mark_redraw(node);
}
@@ -190,7 +190,8 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *
mouse[1] = event->mval[1];
if (SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false)) {
/* The cursor is over the mesh, get the update iteration from the updated active vertex. */
- mask_expand_update_it = ss->filter_cache->mask_update_it[(int)SCULPT_active_vertex_get(ss)];
+ int vi = BKE_pbvh_vertex_index_to_table(ss->pbvh, SCULPT_active_vertex_get(ss));
+ mask_expand_update_it = ss->filter_cache->mask_update_it[vi];
}
else {
/* When the cursor is outside the mesh, affect the entire connected component. */
@@ -312,10 +313,13 @@ typedef struct MaskExpandFloodFillData {
} MaskExpandFloodFillData;
static bool mask_expand_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+ SculptSession *ss, SculptVertRef from_vref, SculptVertRef to_vref, bool is_duplicate, void *userdata)
{
MaskExpandFloodFillData *data = userdata;
+ int to_v = BKE_pbvh_vertex_index_to_table(ss->pbvh, to_vref);
+ int from_v = BKE_pbvh_vertex_index_to_table(ss->pbvh, from_vref);
+
if (!is_duplicate) {
int to_it = ss->filter_cache->mask_update_it[from_v] + 1;
ss->filter_cache->mask_update_it[to_v] = to_it;
@@ -325,8 +329,8 @@ static bool mask_expand_floodfill_cb(
if (data->use_normals) {
float current_normal[3], prev_normal[3];
- SCULPT_vertex_normal_get(ss, to_v, current_normal);
- SCULPT_vertex_normal_get(ss, from_v, prev_normal);
+ SCULPT_vertex_normal_get(ss, to_vref, current_normal);
+ SCULPT_vertex_normal_get(ss, from_vref, prev_normal);
const float from_edge_factor = ss->filter_cache->edge_factor[from_v];
ss->filter_cache->edge_factor[to_v] = dot_v3v3(current_normal, prev_normal) *
from_edge_factor;
@@ -415,13 +419,15 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
else {
ss->filter_cache->prev_mask = MEM_callocN(sizeof(float) * vertex_count, "prev mask");
for (int i = 0; i < vertex_count; i++) {
- ss->filter_cache->prev_mask[i] = SCULPT_vertex_mask_get(ss, i);
+ SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
+ ss->filter_cache->prev_mask[i] = SCULPT_vertex_mask_get(ss, vertex);
}
}
ss->filter_cache->mask_update_last_it = 1;
ss->filter_cache->mask_update_current_it = 1;
- ss->filter_cache->mask_update_it[SCULPT_active_vertex_get(ss)] = 0;
+ ss->filter_cache->mask_update_it[BKE_pbvh_vertex_index_to_table(ss->pbvh, SCULPT_active_vertex_get(ss))] = 0;
copy_v3_v3(ss->filter_cache->mask_expand_initial_co, SCULPT_active_vertex_co_get(ss));
@@ -440,9 +446,11 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
if (use_normals) {
for (int repeat = 0; repeat < 2; repeat++) {
for (int i = 0; i < vertex_count; i++) {
+ SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
float avg = 0.0f;
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
avg += ss->filter_cache->normal_factor[ni.index];
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
diff --git a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
index cfc31e1dcdd..a3216c856bc 100644
--- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
+++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
@@ -87,7 +87,6 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
-
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -108,7 +107,7 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
/* Sample the normal and area of the +X and -X axis individually. */
@@ -168,7 +167,6 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
-
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -217,7 +215,7 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_color.c b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
index 5fdf8415f28..1780d5db8fc 100644
--- a/source/blender/editors/sculpt_paint/sculpt_paint_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
@@ -97,11 +97,11 @@ static void do_color_smooth_task_cb_exec(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
float smooth_color[4];
- SCULPT_neighbor_color_average(ss, smooth_color, vd.index);
+ SCULPT_neighbor_color_average(ss, smooth_color, vd.vertex);
blend_color_interpolate_float(vd.col, vd.col, smooth_color, fade);
if (vd.mvert) {
@@ -124,7 +124,8 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
PBVHColorBufferNode *color_buffer;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COLOR);
+ orig_data.datatype = SCULPT_UNDO_COLOR;
color_buffer = BKE_pbvh_node_color_buffer_get(data->nodes[n]);
@@ -165,7 +166,7 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
/* Density. */
@@ -366,6 +367,10 @@ void SCULPT_do_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
BLI_task_parallel_range(0, totnode, &data, do_paint_brush_task_cb_ex, &settings);
+
+ if (brush->vcol_boundary_factor > 0.0f) {
+ SCULPT_smooth_vcol_boundary(sd, ob, nodes, totnode, brush->vcol_boundary_factor);
+ }
}
static void do_smear_brush_task_cb_exec(void *__restrict userdata,
@@ -396,7 +401,7 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
float current_disp[3];
@@ -419,10 +424,10 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
float vertex_disp[3];
float vertex_disp_norm[3];
- sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co);
+ sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.vertex), vd.co);
const float *neighbor_color = ss->cache->prev_colors[ni.index];
normalize_v3_v3(vertex_disp_norm, vertex_disp);
if (dot_v3v3(current_disp_norm, vertex_disp_norm) >= 0.0f) {
@@ -456,7 +461,7 @@ static void do_smear_store_prev_colors_task_cb_exec(void *__restrict userdata,
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- copy_v4_v4(ss->cache->prev_colors[vd.index], SCULPT_vertex_color_get(ss, vd.index));
+ copy_v4_v4(ss->cache->prev_colors[vd.index], SCULPT_vertex_color_get(ss, vd.vertex));
}
BKE_pbvh_vertex_iter_end;
}
@@ -470,13 +475,17 @@ void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
return;
}
+ SCULPT_vertex_random_access_ensure(ss);
+
const int totvert = SCULPT_vertex_count_get(ss);
if (SCULPT_stroke_is_first_brush_step(ss->cache)) {
if (!ss->cache->prev_colors) {
ss->cache->prev_colors = MEM_callocN(sizeof(float[4]) * totvert, "prev colors");
for (int i = 0; i < totvert; i++) {
- copy_v4_v4(ss->cache->prev_colors[i], SCULPT_vertex_color_get(ss, i));
+ SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
+ copy_v4_v4(ss->cache->prev_colors[i], SCULPT_vertex_color_get(ss, vertex));
}
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c
index a85f805894b..923c838f895 100644
--- a/source/blender/editors/sculpt_paint/sculpt_pose.c
+++ b/source/blender/editors/sculpt_paint/sculpt_pose.c
@@ -172,7 +172,7 @@ static void do_pose_brush_task_cb_ex(void *__restrict userdata,
float final_pos[3];
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -238,7 +238,7 @@ static void pose_brush_grow_factor_task_cb_ex(void *__restrict userdata,
float max = 0.0f;
/* Grow the factor. */
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
float vmask_f = data->prev_mask[ni.index];
max = MAX2(vmask_f, max);
}
@@ -384,7 +384,8 @@ typedef struct PoseFloodFillData {
int current_face_set;
int next_face_set;
int prev_face_set;
- int next_vertex;
+ SculptVertRef next_vertex;
+ int next_vertex_index;
bool next_face_set_found;
@@ -415,10 +416,12 @@ typedef struct PoseFloodFillData {
} PoseFloodFillData;
static bool pose_topology_floodfill_cb(
- SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata)
+ SculptSession *ss, SculptVertRef UNUSED(from_v), SculptVertRef to_vref, bool is_duplicate, void *userdata)
{
PoseFloodFillData *data = userdata;
- const float *co = SCULPT_vertex_co_get(ss, to_v);
+ int to_v = BKE_pbvh_vertex_index_to_table(ss->pbvh, to_vref);
+
+ const float *co = SCULPT_vertex_co_get(ss, to_vref);
if (data->pose_factor) {
data->pose_factor[to_v] = 1.0f;
@@ -444,14 +447,14 @@ static bool pose_topology_floodfill_cb(
}
static bool pose_face_sets_floodfill_cb(
- SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata)
+ SculptSession *ss, SculptVertRef UNUSED(from_v), SculptVertRef to_v, bool is_duplicate, void *userdata)
{
PoseFloodFillData *data = userdata;
- const int index = to_v;
+ const int index = BKE_pbvh_vertex_index_to_table(ss->pbvh, to_v);
bool visit_next = false;
- const float *co = SCULPT_vertex_co_get(ss, index);
+ const float *co = SCULPT_vertex_co_get(ss, to_v);
const bool symmetry_check = SCULPT_check_vertex_pivot_symmetry(
co, data->pose_initial_co, data->symm) &&
!is_duplicate;
@@ -465,11 +468,11 @@ static bool pose_face_sets_floodfill_cb(
if (sculpt_pose_brush_is_vertex_inside_brush_radius(
co, data->pose_initial_co, data->radius, data->symm)) {
- const int visited_face_set = SCULPT_vertex_face_set_get(ss, index);
+ const int visited_face_set = SCULPT_vertex_face_set_get(ss, to_v);
BLI_gset_add(data->visited_face_sets, POINTER_FROM_INT(visited_face_set));
}
else if (symmetry_check) {
- data->current_face_set = SCULPT_vertex_face_set_get(ss, index);
+ data->current_face_set = SCULPT_vertex_face_set_get(ss, to_v);
BLI_gset_add(data->visited_face_sets, POINTER_FROM_INT(data->current_face_set));
}
return true;
@@ -483,11 +486,11 @@ static bool pose_face_sets_floodfill_cb(
GSetIterator gs_iter;
GSET_ITER (gs_iter, data->visited_face_sets) {
const int visited_face_set = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter));
- is_vertex_valid |= SCULPT_vertex_has_face_set(ss, index, visited_face_set);
+ is_vertex_valid |= SCULPT_vertex_has_face_set(ss, to_v, visited_face_set);
}
}
else {
- is_vertex_valid = SCULPT_vertex_has_face_set(ss, index, data->current_face_set);
+ is_vertex_valid = SCULPT_vertex_has_face_set(ss, to_v, data->current_face_set);
}
if (!is_vertex_valid) {
@@ -502,11 +505,11 @@ static bool pose_face_sets_floodfill_cb(
/* Fallback origin accumulation. */
if (symmetry_check) {
- add_v3_v3(data->fallback_origin, SCULPT_vertex_co_get(ss, index));
+ add_v3_v3(data->fallback_origin, SCULPT_vertex_co_get(ss, to_v));
data->fallback_count++;
}
- if (!symmetry_check || SCULPT_vertex_has_unique_face_set(ss, index)) {
+ if (!symmetry_check || SCULPT_vertex_has_unique_face_set(ss, to_v)) {
return visit_next;
}
@@ -515,15 +518,15 @@ static bool pose_face_sets_floodfill_cb(
bool count_as_boundary = false;
SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) {
- int next_face_set_candidate = SCULPT_vertex_face_set_get(ss, ni.index);
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, to_v, ni) {
+ int next_face_set_candidate = SCULPT_vertex_face_set_get(ss, ni.vertex);
/* Check if we can get a valid face set for the next iteration from this neighbor. */
- if (SCULPT_vertex_has_unique_face_set(ss, ni.index) &&
+ if (SCULPT_vertex_has_unique_face_set(ss, ni.vertex) &&
!BLI_gset_haskey(data->visited_face_sets, POINTER_FROM_INT(next_face_set_candidate))) {
if (!data->next_face_set_found) {
data->next_face_set = next_face_set_candidate;
- data->next_vertex = ni.index;
+ data->next_vertex = ni.vertex;
data->next_face_set_found = true;
}
count_as_boundary = true;
@@ -533,7 +536,7 @@ static bool pose_face_sets_floodfill_cb(
/* Origin accumulation. */
if (count_as_boundary) {
- add_v3_v3(data->pose_origin, SCULPT_vertex_co_get(ss, index));
+ add_v3_v3(data->pose_origin, SCULPT_vertex_co_get(ss, to_v));
data->tot_co++;
}
return visit_next;
@@ -557,8 +560,6 @@ void SCULPT_pose_calc_pose_data(Sculpt *sd,
float *r_pose_origin,
float *r_pose_factor)
{
- SCULPT_vertex_random_access_ensure(ss);
-
/* Calculate the pose rotation point based on the boundaries of the brush factor. */
SculptFloodFill flood;
SCULPT_floodfill_init(ss, &flood);
@@ -610,7 +611,7 @@ static void pose_brush_init_task_cb_ex(void *__restrict userdata,
SculptVertexNeighborIter ni;
float avg = 0.0f;
int total = 0;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
avg += data->pose_factor[ni.index];
total++;
}
@@ -680,12 +681,14 @@ static SculptPoseIKChain *pose_ik_chain_init_topology(Sculpt *sd,
const float initial_location[3],
const float radius)
{
+ SCULPT_vertex_random_access_ensure(ss);
const float chain_segment_len = radius * (1.0f + br->pose_offset);
float next_chain_segment_target[3];
int totvert = SCULPT_vertex_count_get(ss);
- int nearest_vertex_index = SCULPT_nearest_vertex_get(sd, ob, initial_location, FLT_MAX, true);
+ SculptVertRef nearest_vertex = SCULPT_nearest_vertex_get(sd, ob, initial_location, FLT_MAX, true);
+ int nearest_vertex_index = BKE_pbvh_vertex_index_to_table(ss->pbvh, nearest_vertex);
/* Init the buffers used to keep track of the changes in the pose factors as more segments are
* added to the IK chain. */
@@ -770,7 +773,8 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets(
int current_face_set = SCULPT_FACE_SET_NONE;
int prev_face_set = SCULPT_FACE_SET_NONE;
- int current_vertex = SCULPT_active_vertex_get(ss);
+ SculptVertRef current_vertex = SCULPT_active_vertex_get(ss);
+ int current_vertex_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, current_vertex);
for (int s = 0; s < ik_chain->tot_segments; s++) {
@@ -826,9 +830,11 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets(
}
static bool pose_face_sets_fk_find_masked_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+ SculptSession *ss, SculptVertRef from_vr, SculptVertRef to_vr, bool is_duplicate, void *userdata)
{
PoseFloodFillData *data = userdata;
+ int from_v = BKE_pbvh_vertex_index_to_table(ss->pbvh, from_vr);
+ int to_v = BKE_pbvh_vertex_index_to_table(ss->pbvh, to_vr);
if (!is_duplicate) {
data->floodfill_it[to_v] = data->floodfill_it[from_v] + 1;
@@ -837,11 +843,11 @@ static bool pose_face_sets_fk_find_masked_floodfill_cb(
data->floodfill_it[to_v] = data->floodfill_it[from_v];
}
- const int to_face_set = SCULPT_vertex_face_set_get(ss, to_v);
+ const int to_face_set = SCULPT_vertex_face_set_get(ss, to_vr);
if (!BLI_gset_haskey(data->visited_face_sets, POINTER_FROM_INT(to_face_set))) {
- if (SCULPT_vertex_has_unique_face_set(ss, to_v) &&
- !SCULPT_vertex_has_unique_face_set(ss, from_v) &&
- SCULPT_vertex_has_face_set(ss, from_v, to_face_set)) {
+ if (SCULPT_vertex_has_unique_face_set(ss, to_vr) &&
+ !SCULPT_vertex_has_unique_face_set(ss, from_vr) &&
+ SCULPT_vertex_has_face_set(ss, from_vr, to_face_set)) {
BLI_gset_add(data->visited_face_sets, POINTER_FROM_INT(to_face_set));
@@ -856,14 +862,14 @@ static bool pose_face_sets_fk_find_masked_floodfill_cb(
}
}
- return SCULPT_vertex_has_face_set(ss, to_v, data->initial_face_set);
+ return SCULPT_vertex_has_face_set(ss, to_vr, data->initial_face_set);
}
static bool pose_face_sets_fk_set_weights_floodfill_cb(
- SculptSession *ss, int UNUSED(from_v), int to_v, bool UNUSED(is_duplicate), void *userdata)
+ SculptSession *ss, SculptVertRef UNUSED(from_v), SculptVertRef to_v, bool UNUSED(is_duplicate), void *userdata)
{
PoseFloodFillData *data = userdata;
- data->fk_weights[to_v] = 1.0f;
+ data->fk_weights[BKE_pbvh_vertex_index_to_table(ss->pbvh, to_v)] = 1.0f;
return !SCULPT_vertex_has_face_set(ss, to_v, data->masked_face_set);
}
@@ -874,7 +880,9 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk(
SculptPoseIKChain *ik_chain = pose_ik_chain_new(1, totvert);
- const int active_vertex = SCULPT_active_vertex_get(ss);
+ const SculptVertRef active_vertex = SCULPT_active_vertex_get(ss);
+ const int active_vertex_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, active_vertex);
+
const int active_face_set = SCULPT_active_face_set_get(ss);
SculptFloodFill flood;
@@ -882,7 +890,7 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk(
SCULPT_floodfill_add_initial(&flood, active_vertex);
PoseFloodFillData fdata;
fdata.floodfill_it = MEM_calloc_arrayN(totvert, sizeof(int), "floodfill iteration");
- fdata.floodfill_it[active_vertex] = 1;
+ fdata.floodfill_it[active_vertex_i] = 1;
fdata.initial_face_set = active_face_set;
fdata.masked_face_set = SCULPT_FACE_SET_NONE;
fdata.target_face_set = SCULPT_FACE_SET_NONE;
@@ -895,9 +903,11 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk(
int origin_count = 0;
float origin_acc[3] = {0.0f};
for (int i = 0; i < totvert; i++) {
- if (fdata.floodfill_it[i] != 0 && SCULPT_vertex_has_face_set(ss, i, fdata.initial_face_set) &&
- SCULPT_vertex_has_face_set(ss, i, fdata.masked_face_set)) {
- add_v3_v3(origin_acc, SCULPT_vertex_co_get(ss, i));
+ SculptVertRef vref = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
+ if (fdata.floodfill_it[i] != 0 && SCULPT_vertex_has_face_set(ss, vref, fdata.initial_face_set) &&
+ SCULPT_vertex_has_face_set(ss, vref, fdata.masked_face_set)) {
+ add_v3_v3(origin_acc, SCULPT_vertex_co_get(ss, vref));
origin_count++;
}
}
@@ -906,10 +916,12 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk(
float target_acc[3] = {0.0f};
if (fdata.target_face_set != fdata.masked_face_set) {
for (int i = 0; i < totvert; i++) {
+ SculptVertRef vref = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
if (fdata.floodfill_it[i] != 0 &&
- SCULPT_vertex_has_face_set(ss, i, fdata.initial_face_set) &&
- SCULPT_vertex_has_face_set(ss, i, fdata.target_face_set)) {
- add_v3_v3(target_acc, SCULPT_vertex_co_get(ss, i));
+ SCULPT_vertex_has_face_set(ss, vref, fdata.initial_face_set) &&
+ SCULPT_vertex_has_face_set(ss, vref, fdata.target_face_set)) {
+ add_v3_v3(target_acc, SCULPT_vertex_co_get(ss, vref));
target_count++;
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c
index 4c0795eb0f7..bd591ff9ace 100644
--- a/source/blender/editors/sculpt_paint/sculpt_smooth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c
@@ -58,11 +58,18 @@
#include "RNA_define.h"
#include "bmesh.h"
-
+#ifdef PROXY_ADVANCED
+/* clang-format off */
+#include "BKE_DerivedMesh.h"
+#include "../../blenkernel/intern/pbvh_intern.h"
+/* clang-format on */
+#endif
#include <math.h>
#include <stdlib.h>
-void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3], int index)
+void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
+ float result[3],
+ SculptVertRef index)
{
float avg[3] = {0.0f, 0.0f, 0.0f};
int total = 0;
@@ -74,14 +81,14 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3],
neighbor_count++;
if (is_boundary) {
/* Boundary vertices use only other boundary vertices. */
- if (SCULPT_vertex_is_boundary(ss, ni.index)) {
- add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.index));
+ if (SCULPT_vertex_is_boundary(ss, ni.vertex)) {
+ add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.vertex));
total++;
}
}
else {
/* Interior vertices use all neighbors. */
- add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.index));
+ add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.vertex));
total++;
}
}
@@ -152,14 +159,14 @@ void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], BMVert
/* Generic functions for laplacian smoothing. These functions do not take boundary vertices into
* account. */
-void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int index)
+void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], SculptVertRef index)
{
float avg[3] = {0.0f, 0.0f, 0.0f};
int total = 0;
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) {
- add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.index));
+ add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.vertex));
total++;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
@@ -172,14 +179,14 @@ void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int inde
}
}
-float SCULPT_neighbor_mask_average(SculptSession *ss, int index)
+float SCULPT_neighbor_mask_average(SculptSession *ss, SculptVertRef index)
{
float avg = 0.0f;
int total = 0;
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) {
- avg += SCULPT_vertex_mask_get(ss, ni.index);
+ avg += SCULPT_vertex_mask_get(ss, ni.vertex);
total++;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
@@ -190,14 +197,14 @@ float SCULPT_neighbor_mask_average(SculptSession *ss, int index)
return SCULPT_vertex_mask_get(ss, index);
}
-void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index)
+void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], SculptVertRef index)
{
float avg[4] = {0.0f, 0.0f, 0.0f, 0.0f};
int total = 0;
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) {
- add_v4_v4(avg, SCULPT_vertex_color_get(ss, ni.index));
+ add_v4_v4(avg, SCULPT_vertex_color_get(ss, ni.vertex));
total++;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
@@ -231,6 +238,7 @@ static void do_enhance_details_brush_task_cb_ex(void *__restrict userdata,
const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
+
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -242,7 +250,7 @@ static void do_enhance_details_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
float disp[3];
@@ -274,8 +282,10 @@ static void SCULPT_enhance_details_brush(Sculpt *sd,
for (int i = 0; i < totvert; i++) {
float avg[3];
- SCULPT_neighbor_coords_average(ss, avg, i);
- sub_v3_v3v3(ss->cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, i));
+ SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
+
+ SCULPT_neighbor_coords_average(ss, avg, vertex);
+ sub_v3_v3v3(ss->cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, vertex));
}
}
@@ -291,6 +301,88 @@ static void SCULPT_enhance_details_brush(Sculpt *sd,
BLI_task_parallel_range(0, totnode, &data, do_enhance_details_brush_task_cb_ex, &settings);
}
+#ifdef PROXY_ADVANCED
+static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ const Brush *brush = data->brush;
+ const bool smooth_mask = data->smooth_mask;
+ float bstrength = data->strength;
+
+ PBVHVertexIter vd;
+
+ CLAMP(bstrength, 0.0f, 1.0f);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ PBVHNode **nodes = data->nodes;
+ ProxyVertArray *p = &nodes[n]->proxyverts;
+
+ for (int i = 0; i < p->size; i++) {
+ float co[3] = {0.0f, 0.0f, 0.0f};
+ int ni = 0;
+
+# if 1
+ if (sculpt_brush_test_sq_fn(&test, p->co[i])) {
+ const float fade = bstrength * SCULPT_brush_strength_factor(
+ ss,
+ brush,
+ p->co[i],
+ sqrtf(test.dist),
+ p->no[i],
+ p->fno[i],
+ smooth_mask ? 0.0f : (p->mask ? p->mask[i] : 0.0f),
+ p->index[i],
+ thread_id);
+# else
+ if (1) {
+ const float fade = 1.0;
+# endif
+
+ while (ni < MAX_PROXY_NEIGHBORS && p->neighbors[i][ni].node >= 0) {
+ ProxyKey *key = p->neighbors[i] + ni;
+ PBVHNode *n2 = ss->pbvh->nodes + key->node;
+
+ // printf("%d %d %d %p\n", key->node, key->pindex, ss->pbvh->totnode, n2);
+
+ if (key->pindex < 0 || key->pindex >= n2->proxyverts.size) {
+ printf("corruption!\n");
+ fflush(stdout);
+ ni++;
+ continue;
+ }
+
+ if (n2->proxyverts.co) {
+ add_v3_v3(co, n2->proxyverts.co[key->pindex]);
+ ni++;
+ }
+ }
+
+ // printf("ni %d\n", ni);
+
+ if (ni > 2) {
+ mul_v3_fl(co, 1.0f / (float)ni);
+ }
+ else {
+ copy_v3_v3(co, p->co[i]);
+ }
+
+ // printf("%f %f %f ", co[0], co[1], co[2]);
+
+ interp_v3_v3v3(p->co[i], p->co[i], co, fade);
+ }
+ }
+}
+
+#else
static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
@@ -325,17 +417,17 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f),
- vd.index,
+ vd.vertex,
thread_id);
if (smooth_mask) {
- float val = SCULPT_neighbor_mask_average(ss, vd.index) - *vd.mask;
+ float val = SCULPT_neighbor_mask_average(ss, vd.vertex) - *vd.mask;
val *= fade * bstrength;
*vd.mask += val;
CLAMP(*vd.mask, 0.0f, 1.0f);
}
else {
float avg[3], val[3];
- SCULPT_neighbor_coords_average_interior(ss, avg, vd.index);
+ SCULPT_neighbor_coords_average_interior(ss, avg, vd.vertex);
sub_v3_v3v3(val, avg, vd.co);
madd_v3_v3v3fl(val, vd.co, val, fade);
SCULPT_clip(sd, ss, vd.co, val);
@@ -346,6 +438,7 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
}
BKE_pbvh_vertex_iter_end;
}
+#endif
void SCULPT_smooth(Sculpt *sd,
Object *ob,
@@ -373,9 +466,18 @@ void SCULPT_smooth(Sculpt *sd,
return;
}
- SCULPT_vertex_random_access_ensure(ss);
+ if (type != PBVH_BMESH) {
+ SCULPT_vertex_random_access_ensure(ss);
+ }
+
SCULPT_boundary_info_ensure(ob);
+#ifdef PROXY_ADVANCED
+ int datamask = PV_CO | PV_NEIGHBORS | PV_NO | PV_INDEX | PV_MASK;
+ BKE_pbvh_ensure_proxyarrays(ss, ss->pbvh, nodes, totnode, datamask);
+
+ BKE_pbvh_load_proxyarrays(ss->pbvh, nodes, totnode, PV_CO | PV_NO | PV_MASK);
+#endif
for (iteration = 0; iteration <= count; iteration++) {
const float strength = (iteration != count) ? 1.0f : last;
@@ -391,6 +493,10 @@ void SCULPT_smooth(Sculpt *sd,
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_task_cb_ex, &settings);
+
+#ifdef PROXY_ADVANCED
+ BKE_pbvh_gather_proxyarray(ss->pbvh, nodes, totnode);
+#endif
}
}
@@ -414,7 +520,7 @@ void SCULPT_surface_smooth_laplacian_step(SculptSession *ss,
float *disp,
const float co[3],
float (*laplacian_disp)[3],
- const int v_index,
+ const SculptVertRef v_index,
const float origco[3],
const float alpha)
{
@@ -422,10 +528,12 @@ void SCULPT_surface_smooth_laplacian_step(SculptSession *ss,
float weigthed_o[3], weigthed_q[3], d[3];
SCULPT_neighbor_coords_average(ss, laplacian_smooth_co, v_index);
+ int index = BKE_pbvh_vertex_index_to_table(ss->pbvh, v_index);
+
mul_v3_v3fl(weigthed_o, origco, alpha);
mul_v3_v3fl(weigthed_q, co, 1.0f - alpha);
add_v3_v3v3(d, weigthed_o, weigthed_q);
- sub_v3_v3v3(laplacian_disp[v_index], laplacian_smooth_co, d);
+ sub_v3_v3v3(laplacian_disp[index], laplacian_smooth_co, d);
sub_v3_v3v3(disp, laplacian_smooth_co, co);
}
@@ -433,22 +541,25 @@ void SCULPT_surface_smooth_laplacian_step(SculptSession *ss,
void SCULPT_surface_smooth_displace_step(SculptSession *ss,
float *co,
float (*laplacian_disp)[3],
- const int v_index,
+ const SculptVertRef v_index,
const float beta,
const float fade)
{
float b_avg[3] = {0.0f, 0.0f, 0.0f};
float b_current_vertex[3];
int total = 0;
+ int index = BKE_pbvh_vertex_index_to_table(ss->pbvh, v_index);
+
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, v_index, ni) {
add_v3_v3(b_avg, laplacian_disp[ni.index]);
total++;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
if (total > 0) {
mul_v3_v3fl(b_current_vertex, b_avg, (1.0f - beta) / total);
- madd_v3_v3fl(b_current_vertex, laplacian_disp[v_index], beta);
+ madd_v3_v3fl(b_current_vertex, laplacian_disp[index], beta);
mul_v3_fl(b_current_vertex, clamp_f(fade, 0.0f, 1.0f));
sub_v3_v3(co, b_current_vertex);
}
@@ -471,11 +582,12 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
SCULPT_orig_vert_data_update(&orig_data, &vd);
+
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
@@ -486,12 +598,12 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex(
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
float disp[3];
SCULPT_surface_smooth_laplacian_step(
- ss, disp, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.index, orig_data.co, alpha);
+ ss, disp, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.vertex, orig_data.co, alpha);
madd_v3_v3fl(vd.co, disp, clamp_f(fade, 0.0f, 1.0f));
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
@@ -528,10 +640,10 @@ static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex(
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
- vd.index,
+ vd.vertex,
thread_id);
SCULPT_surface_smooth_displace_step(
- ss, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.index, beta, fade);
+ ss, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.vertex, beta, fade);
}
BKE_pbvh_vertex_iter_end;
}
@@ -564,3 +676,232 @@ void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in
0, totnode, &data, SCULPT_do_surface_smooth_brush_displace_task_cb_ex, &settings);
}
}
+
+static void do_smooth_vcol_boundary_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ const Brush *brush = data->brush;
+ const bool smooth_mask = data->smooth_mask;
+ float bstrength = data->strength;
+
+ PBVHVertexIter vd;
+
+ CLAMP(bstrength, 0.0f, 1.0f);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ float avg[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float tot = 0.0f;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (!vd.col) {
+ continue;
+ }
+
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float fade = bstrength * SCULPT_brush_strength_factor(
+ ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f),
+ vd.vertex,
+ thread_id);
+
+ madd_v3_v3fl(avg, vd.col, fade);
+ tot += fade;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+
+ if (tot == 0.0f) {
+ return;
+ }
+ tot = 1.0f / tot;
+
+ mul_v3_fl(avg, tot);
+
+ float exp = brush->vcol_boundary_exponent;
+ //detect bad value
+
+ if (exp == 0.0f) {
+ exp = 1.0f;
+ }
+
+ //#define SHARPEN_VCOL_BOUNDARY
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float fade = bstrength * SCULPT_brush_strength_factor(
+ ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f),
+ vd.vertex,
+ thread_id);
+ if (!vd.col) {
+ continue;
+ }
+
+ float avg2[3], avg3[3], val[3];
+ float tot2 = 0.0f, tot4 = 0.0f;
+
+ copy_v4_v4(avg, vd.col);
+
+ zero_v3(avg2);
+ zero_v3(avg3);
+
+ madd_v3_v3fl(avg2, vd.co, 0.5f);
+ tot2 += 0.5f;
+
+#ifdef SHARPEN_VCOL_BOUNDARY
+ float ntot = 0.0f;
+ float colavg[4], tot3 = 0.0f;
+ zero_v4(colavg);
+#endif
+
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
+ const float *col = SCULPT_vertex_color_get(ss, ni.vertex);
+ const float *co = SCULPT_vertex_co_get(ss, ni.vertex);
+
+ // simple color metric. TODO: plug in appropriate color space code?
+ float dv[4];
+ sub_v4_v4v4(dv, col, avg);
+ float w = (fabs(dv[0]) + fabs(dv[1]) + fabs(dv[2]) + fabs(dv[3])) / 4.0;
+
+ w = powf(w, exp);
+
+ //w *= w;
+
+#ifdef SHARPEN_VCOL_BOUNDARY
+ float w2 = -1.0f;
+ madd_v4_v4fl(colavg, col, w2);
+ tot3 += w2;
+ ntot += 1.0f;
+#endif
+
+ madd_v3_v3fl(avg3, co, 1.0f);
+ tot4 += 1.0f;
+
+ madd_v3_v3fl(avg2, co, w);
+ tot2 += w;
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ if (tot2 == 0.0f) {
+ continue;
+ }
+
+ if (tot4 > 0.0f) {
+ mul_v3_fl(avg3, 1.0f / tot4);
+ }
+
+#ifdef SHARPEN_VCOL_BOUNDARY
+ float w2 = ntot*40.0f;
+ madd_v4_v4fl(colavg, vd.col, w2);
+ tot3 += w2;
+
+ if (tot3 > 0.0f) {
+ mul_v4_fl(colavg, 1.0f / tot3);
+ }
+
+ //clamp_v4(colavg, 0.0f, 1.0f);
+ //negative numbers are undesirable, but dunno if I should clip above 1.0 or not except for alpha
+ for (int i=0; i<4; i++) {
+ colavg[i] = MAX2(colavg[i], 0.0f);
+ colavg[i] = MIN2(colavg[i], 1.0f);
+ }
+ //colavg[3] = MIN2(colavg[3], 1.0f);
+
+ interp_v4_v4v4(vd.col, vd.col, colavg, fade*0.25);
+#endif
+
+ //try to avoid perfectly colinear triangles, and the normal discontinuities they create,
+ //by blending slightly with unweighted smoothed position
+ mul_v3_fl(avg2, 1.0f / tot2);
+ interp_v3_v3v3(avg2, avg2, avg3, 0.025);
+
+ sub_v3_v3v3(val, avg2, vd.co);
+ madd_v3_v3v3fl(val, vd.co, val, fade);
+ SCULPT_clip(sd, ss, vd.co, val);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_smooth_vcol_boundary(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, float bstrength)
+{
+ SculptSession *ss = ob->sculpt;
+
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const int max_iterations = 4;
+ const float fract = 1.0f / max_iterations;
+ PBVHType type = BKE_pbvh_type(ss->pbvh);
+ int iteration, count;
+ float last;
+
+ CLAMP(bstrength, 0.0f, 1.0f);
+
+ count = (int)(bstrength * max_iterations);
+ last = max_iterations * (bstrength - count * fract);
+
+ if (type == PBVH_FACES && !ss->pmap) {
+ BLI_assert(!"sculpt smooth: pmap missing");
+ return;
+ }
+
+ if (type != PBVH_BMESH) {
+ SCULPT_vertex_random_access_ensure(ss);
+ }
+
+ SCULPT_boundary_info_ensure(ob);
+
+#ifdef PROXY_ADVANCED
+ int datamask = PV_CO | PV_NEIGHBORS | PV_NO | PV_INDEX | PV_MASK;
+ BKE_pbvh_ensure_proxyarrays(ss, ss->pbvh, nodes, totnode, datamask);
+
+ BKE_pbvh_load_proxyarrays(ss->pbvh, nodes, totnode, PV_CO | PV_NO | PV_MASK);
+#endif
+ for (iteration = 0; iteration <= count; iteration++) {
+ const float strength = (iteration != count) ? 1.0f : last;
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .smooth_mask = false,
+ .strength = strength,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(
+ 0, totnode, &data, do_smooth_vcol_boundary_brush_task_cb_ex, &settings);
+
+#ifdef PROXY_ADVANCED
+ BKE_pbvh_gather_proxyarray(ss->pbvh, nodes, totnode);
+#endif
+ }
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c
index 4554ea178ab..934c0432633 100644
--- a/source/blender/editors/sculpt_paint/sculpt_transform.c
+++ b/source/blender/editors/sculpt_paint/sculpt_transform.c
@@ -159,7 +159,7 @@ static void sculpt_transform_task_cb(void *__restrict userdata,
PBVHNode *node = data->nodes[i];
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i], SCULPT_UNDO_COORDS);
PBVHVertexIter vd;
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index ec103bd2b98..6df6f8aa705 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -116,6 +116,7 @@ typedef struct UndoSculpt {
} UndoSculpt;
static UndoSculpt *sculpt_undo_get_nodes(void);
+void sculpt_undo_print_nodes(void *active);
static void update_cb(PBVHNode *node, void *rebuild)
{
@@ -133,6 +134,8 @@ struct PartialUpdateData {
char *modified_grids;
};
+static UndoSculpt *sculpt_undosys_step_get_nodes(UndoStep *us_p);
+
/**
* A version of #update_cb that tests for 'ME_VERT_PBVH_UPDATE'
*/
@@ -180,14 +183,16 @@ static bool sculpt_undo_restore_deformed(
return false;
}
-static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, SculptUndoNode *unode)
+static bool sculpt_undo_restore_coords(bContext *C,
+ Depsgraph *depsgraph,
+ SculptUndoNode *unode)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = OBACT(view_layer);
SculptSession *ss = ob->sculpt;
SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
MVert *mvert;
- int *index;
+ SculptVertRef *index;
if (unode->maxvert) {
/* Regular mesh restore. */
@@ -221,18 +226,18 @@ static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, Sculpt
if (unode->orig_co) {
if (ss->deform_modifiers_active) {
for (int i = 0; i < unode->totvert; i++) {
- sculpt_undo_restore_deformed(ss, unode, i, index[i], vertCos[index[i]]);
+ sculpt_undo_restore_deformed(ss, unode, i, index[i].i, vertCos[index[i].i]);
}
}
else {
for (int i = 0; i < unode->totvert; i++) {
- swap_v3_v3(vertCos[index[i]], unode->orig_co[i]);
+ swap_v3_v3(vertCos[index[i].i], unode->orig_co[i]);
}
}
}
else {
for (int i = 0; i < unode->totvert; i++) {
- swap_v3_v3(vertCos[index[i]], unode->co[i]);
+ swap_v3_v3(vertCos[index[i].i], unode->co[i]);
}
}
@@ -249,21 +254,21 @@ static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, Sculpt
if (unode->orig_co) {
if (ss->deform_modifiers_active) {
for (int i = 0; i < unode->totvert; i++) {
- sculpt_undo_restore_deformed(ss, unode, i, index[i], mvert[index[i]].co);
- mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
+ sculpt_undo_restore_deformed(ss, unode, i, index[i].i, mvert[index[i].i].co);
+ mvert[index[i].i].flag |= ME_VERT_PBVH_UPDATE;
}
}
else {
for (int i = 0; i < unode->totvert; i++) {
- swap_v3_v3(mvert[index[i]].co, unode->orig_co[i]);
- mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
+ swap_v3_v3(mvert[index[i].i].co, unode->orig_co[i]);
+ mvert[index[i].i].flag |= ME_VERT_PBVH_UPDATE;
}
}
}
else {
for (int i = 0; i < unode->totvert; i++) {
- swap_v3_v3(mvert[index[i]].co, unode->co[i]);
- mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
+ swap_v3_v3(mvert[index[i].i].co, unode->co[i]);
+ mvert[index[i].i].flag |= ME_VERT_PBVH_UPDATE;
}
}
}
@@ -303,7 +308,7 @@ static bool sculpt_undo_restore_hidden(bContext *C, SculptUndoNode *unode)
MVert *mvert = ss->mvert;
for (int i = 0; i < unode->totvert; i++) {
- MVert *v = &mvert[unode->index[i]];
+ MVert *v = &mvert[unode->index[i].i];
if ((BLI_BITMAP_TEST(unode->vert_hidden, i) != 0) != ((v->flag & ME_HIDE) != 0)) {
BLI_BITMAP_FLIP(unode->vert_hidden, i);
v->flag ^= ME_HIDE;
@@ -330,13 +335,13 @@ static bool sculpt_undo_restore_color(bContext *C, SculptUndoNode *unode)
if (unode->maxvert) {
/* regular mesh restore */
- int *index = unode->index;
+ SculptVertRef *index = unode->index;
MVert *mvert = ss->mvert;
MPropCol *vcol = ss->vcol;
for (int i = 0; i < unode->totvert; i++) {
- copy_v4_v4(vcol[index[i]].color, unode->col[i]);
- mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
+ swap_v4_v4(vcol[index[i].i].color, unode->col[i]);
+ mvert[index[i].i].flag |= ME_VERT_PBVH_UPDATE;
}
}
return true;
@@ -350,7 +355,7 @@ static bool sculpt_undo_restore_mask(bContext *C, SculptUndoNode *unode)
SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
MVert *mvert;
float *vmask;
- int *index;
+ SculptVertRef *index;
if (unode->maxvert) {
/* Regular mesh restore. */
@@ -360,9 +365,9 @@ static bool sculpt_undo_restore_mask(bContext *C, SculptUndoNode *unode)
vmask = ss->vmask;
for (int i = 0; i < unode->totvert; i++) {
- if (vmask[index[i]] != unode->mask[i]) {
- SWAP(float, vmask[index[i]], unode->mask[i]);
- mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
+ if (vmask[index[i].i] != unode->mask[i]) {
+ SWAP(float, vmask[index[i].i], unode->mask[i]);
+ mvert[index[i].i].flag |= ME_VERT_PBVH_UPDATE;
}
}
}
@@ -421,7 +426,7 @@ static void sculpt_undo_bmesh_restore_generic(SculptUndoNode *unode, Object *ob,
unode->applied = true;
}
- if (unode->type == SCULPT_UNDO_MASK) {
+ if (unode->type == SCULPT_UNDO_MASK || unode->type == SCULPT_UNDO_COLOR) {
int totnode;
PBVHNode **nodes;
@@ -460,6 +465,8 @@ static void sculpt_undo_bmesh_enable(Object *ob, SculptUndoNode *unode)
/* Restore the BMLog using saved entries. */
ss->bm_log = BM_log_from_existing_entries_create(ss->bm, unode->bm_entry);
+ BM_log_set_cd_offsets(
+ ss->bm_log, ss->cd_origco_offset, ss->cd_origno_offset, ss->cd_origvcol_offset);
}
static void sculpt_undo_bmesh_restore_begin(bContext *C,
@@ -499,6 +506,8 @@ static void sculpt_undo_bmesh_restore_end(bContext *C,
SCULPT_dynamic_topology_disable(C, NULL);
unode->applied = true;
}
+
+ BM_mesh_elem_index_ensure(ss->bm, BM_VERT);
}
static void sculpt_undo_geometry_store_data(SculptUndoNodeGeometry *geometry, Object *object)
@@ -590,17 +599,25 @@ static int sculpt_undo_bmesh_restore(bContext *C,
Object *ob,
SculptSession *ss)
{
+ if (ss->bm_log) {
+ BM_log_set_cd_offsets(
+ ss->bm_log, ss->cd_origco_offset, ss->cd_origno_offset, ss->cd_origvcol_offset);
+ }
+
switch (unode->type) {
case SCULPT_UNDO_DYNTOPO_BEGIN:
sculpt_undo_bmesh_restore_begin(C, unode, ob, ss);
+ SCULPT_vertex_random_access_ensure(ss);
return true;
case SCULPT_UNDO_DYNTOPO_END:
sculpt_undo_bmesh_restore_end(C, unode, ob, ss);
+ SCULPT_vertex_random_access_ensure(ss);
return true;
default:
if (ss->bm_log) {
sculpt_undo_bmesh_restore_generic(unode, ob, ss);
+ SCULPT_vertex_random_access_ensure(ss);
return true;
}
break;
@@ -664,7 +681,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
- if (lb->first) {
+ if (!ss->bm && lb->first) {
unode = lb->first;
if (unode->type == SCULPT_UNDO_FACE_SETS) {
sculpt_undo_restore_face_sets(C, unode);
@@ -719,6 +736,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
* continue. */
if (unode->maxvert) {
if (ss->totvert != unode->maxvert) {
+ printf("error! %s\n", __func__);
continue;
}
}
@@ -859,6 +877,9 @@ static void sculpt_undo_free_list(ListBase *lb)
if (unode->co) {
MEM_freeN(unode->co);
}
+ if (unode->nodemap) {
+ MEM_freeN(unode->nodemap);
+ }
if (unode->no) {
MEM_freeN(unode->no);
}
@@ -888,6 +909,7 @@ static void sculpt_undo_free_list(ListBase *lb)
if (unode->bm_entry) {
BM_log_entry_drop(unode->bm_entry);
+ unode->bm_entry = NULL;
}
sculpt_undo_geometry_free_data(&unode->geometry_original);
@@ -927,7 +949,28 @@ static bool sculpt_undo_cleanup(bContext *C, ListBase *lb)
}
#endif
-SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node)
+static int hash_sculpt_colors(SculptUndoNode *node)
+{
+ if (!node->col) {
+ return -1;
+ }
+
+ int i = 0;
+ int hash = 0;
+
+ for (i = 0; i < node->totvert; i++) {
+ float *col = node->col[i];
+
+ for (int j = 0; j < 4; j++) {
+ hash = hash ^ (int)(col[j] * 2048.0f * 2048.0f);
+ hash += (1 << 23) - 1;
+ }
+ }
+
+ return hash;
+}
+
+SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node, SculptUndoType type)
{
UndoSculpt *usculpt = sculpt_undo_get_nodes();
@@ -935,7 +978,19 @@ SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node)
return NULL;
}
- return BLI_findptr(&usculpt->nodes, node, offsetof(SculptUndoNode, node));
+ if (type < 0) {
+ return BLI_findptr(&usculpt->nodes, node, offsetof(SculptUndoNode, node));
+ }
+
+ SculptUndoNode *unode;
+
+ for (unode = usculpt->nodes.first; unode; unode = unode->next) {
+ if (unode->node == node && type == unode->type) {
+ return unode;
+ }
+ }
+
+ return NULL;
}
SculptUndoNode *SCULPT_undo_get_first_node()
@@ -1084,7 +1139,7 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt
else {
/* Regular mesh. */
unode->maxvert = ss->totvert;
-
+
const size_t alloc_size = sizeof(*unode->index) * (size_t)allvert;
unode->index = MEM_callocN(alloc_size, "SculptUndoNode.index");
usculpt->undo_size += alloc_size;
@@ -1104,6 +1159,9 @@ static void sculpt_undo_store_coords(Object *ob, SculptUndoNode *unode)
SculptSession *ss = ob->sculpt;
PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ SCULPT_orig_vert_data_unode_init(&orig_data, ob, unode);
+
BKE_pbvh_vertex_iter_begin(ss->pbvh, unode->node, vd, PBVH_ITER_ALL)
{
copy_v3_v3(unode->co[vd.i], vd.co);
@@ -1115,7 +1173,11 @@ static void sculpt_undo_store_coords(Object *ob, SculptUndoNode *unode)
}
if (ss->deform_modifiers_active) {
- copy_v3_v3(unode->orig_co[vd.i], ss->orig_cos[unode->index[vd.i]]);
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+
+ int index = BKE_pbvh_vertex_index_to_table(ss->pbvh, unode->index[vd.i]);
+
+ copy_v3_v3(unode->orig_co[vd.i], orig_data.co);
}
}
BKE_pbvh_vertex_iter_end;
@@ -1159,6 +1221,8 @@ static void sculpt_undo_store_color(Object *ob, SculptUndoNode *unode)
SculptSession *ss = ob->sculpt;
PBVHVertexIter vd;
+ //unode->gen++;
+
BKE_pbvh_vertex_iter_begin(ss->pbvh, unode->node, vd, PBVH_ITER_ALL)
{
copy_v4_v4(unode->col[vd.i], vd.col);
@@ -1222,7 +1286,10 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt
SculptUndoNode *unode = usculpt->nodes.first;
+ bool new_node = false;
+
if (unode == NULL) {
+ new_node = true;
unode = MEM_callocN(sizeof(*unode), __func__);
BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname));
@@ -1230,7 +1297,7 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt
unode->applied = true;
if (type == SCULPT_UNDO_DYNTOPO_END) {
- unode->bm_entry = BM_log_entry_add(ss->bm_log);
+ unode->bm_entry = BM_log_entry_add(ss->bm, ss->bm_log);
BM_log_before_all_removed(ss->bm, ss->bm_log);
}
else if (type == SCULPT_UNDO_DYNTOPO_BEGIN) {
@@ -1242,17 +1309,21 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt
SculptUndoNodeGeometry *geometry = &unode->geometry_bmesh_enter;
sculpt_undo_geometry_store_data(geometry, ob);
- unode->bm_entry = BM_log_entry_add(ss->bm_log);
+ unode->bm_entry = BM_log_entry_add(ss->bm, ss->bm_log);
BM_log_all_added(ss->bm, ss->bm_log);
}
else {
- unode->bm_entry = BM_log_entry_add(ss->bm_log);
+ unode->bm_entry = BM_log_entry_add(ss->bm, ss->bm_log);
}
BLI_addtail(&usculpt->nodes, unode);
}
if (node) {
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ unode->bm_entry = BM_log_entry_check_customdata(ss->bm, ss->bm_log);
+ }
+
switch (type) {
case SCULPT_UNDO_COORDS:
case SCULPT_UNDO_MASK:
@@ -1260,41 +1331,121 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt
* original positions are logged. */
BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL)
{
- BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset);
+ void *dummy;
+ BKE_pbvh_bmesh_update_origvert(ss->pbvh, vd.bm_vert, &dummy, &dummy, &dummy);
+ // BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset, false);
}
BKE_pbvh_vertex_iter_end;
break;
case SCULPT_UNDO_HIDDEN: {
- GSetIterator gs_iter;
- GSet *faces = BKE_pbvh_bmesh_node_faces(node);
+ TableGSet *faces = BKE_pbvh_bmesh_node_faces(node);
+ BMFace *f;
+
BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL)
{
- BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset);
+ BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset, true);
+ // BKE_pbvh_bmesh_update_origvert(ss->pbvh, vd.bm_vert, &dummy, &dummy, &dummy);
}
BKE_pbvh_vertex_iter_end;
- GSET_ITER (gs_iter, faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+ TGSET_ITER (f, faces) {
BM_log_face_modified(ss->bm_log, f);
}
+ TGSET_ITER_END
break;
}
+ case SCULPT_UNDO_COLOR: {
+#if 1
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL)
+ {
+ void *dummy;
+ BKE_pbvh_bmesh_update_origvert(ss->pbvh, vd.bm_vert, NULL, NULL, &dummy);
+ }
+ BKE_pbvh_vertex_iter_end;
+#endif
+ break;
+ }
+ case SCULPT_UNDO_FACE_SETS: {
+ TableGSet *faces = BKE_pbvh_bmesh_node_faces(node);
+ BMFace *f;
+
+ TGSET_ITER (f, faces) {
+ BM_log_face_modified(ss->bm_log, f);
+ }
+ TGSET_ITER_END
+
+ break;
+ }
case SCULPT_UNDO_DYNTOPO_BEGIN:
case SCULPT_UNDO_DYNTOPO_END:
case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
case SCULPT_UNDO_GEOMETRY:
- case SCULPT_UNDO_FACE_SETS:
- case SCULPT_UNDO_COLOR:
break;
}
}
+ if (new_node) {
+ sculpt_undo_print_nodes(NULL);
+ }
+
return unode;
}
-SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType type)
+bool SCULPT_ensure_dyntopo_node_undo(Object *ob,
+ PBVHNode *node,
+ SculptUndoType type,
+ int extraType)
+{
+ SculptSession *ss = ob->sculpt;
+ UndoSculpt *usculpt = sculpt_undo_get_nodes();
+ SculptUndoNode *unode = usculpt->nodes.first;
+
+ if (!unode || unode->type != type) {
+ unode = sculpt_undo_alloc_node_type(ob, type);
+
+ BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname));
+
+ unode->type = type;
+ unode->applied = true;
+ unode->bm_entry = BM_log_entry_add(ss->bm, ss->bm_log);
+
+ return SCULPT_ensure_dyntopo_node_undo(ob, node, type, extraType);
+ }
+
+ int n = BKE_pbvh_get_node_index(ss->pbvh, node);
+
+ if (unode->nodemap_size <= n) {
+ int newsize = (n + 1) * 2;
+
+ if (!unode->nodemap) {
+ unode->nodemap = MEM_callocN(sizeof(*unode->nodemap) * newsize, "unode->nodemap");
+ }
+ else {
+ unode->nodemap = MEM_recallocN(unode->nodemap, sizeof(*unode->nodemap) * newsize);
+ }
+
+ unode->nodemap_size = newsize;
+ }
+
+ if (unode->nodemap[n]) {
+ return false;
+ }
+
+ unode->nodemap[n] = 1;
+ sculpt_undo_bmesh_push(ob, node, type);
+
+ if (extraType >= 0) {
+ sculpt_undo_bmesh_push(ob, node, extraType);
+ }
+
+ return true;
+}
+
+SculptUndoNode *SCULPT_undo_push_node(Object *ob,
+ PBVHNode *node,
+ SculptUndoType type)
{
SculptSession *ss = ob->sculpt;
SculptUndoNode *unode;
@@ -1308,20 +1459,24 @@ SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType
/* Dynamic topology stores only one undo node per stroke,
* regardless of the number of PBVH nodes modified. */
unode = sculpt_undo_bmesh_push(ob, node, type);
+ sculpt_undo_print_nodes(NULL);
BLI_thread_unlock(LOCK_CUSTOM1);
return unode;
}
if (type == SCULPT_UNDO_GEOMETRY) {
unode = sculpt_undo_geometry_push(ob, type);
+ sculpt_undo_print_nodes(NULL);
BLI_thread_unlock(LOCK_CUSTOM1);
return unode;
}
if (type == SCULPT_UNDO_FACE_SETS) {
unode = sculpt_undo_face_sets_push(ob, type);
+ sculpt_undo_print_nodes(NULL);
BLI_thread_unlock(LOCK_CUSTOM1);
return unode;
}
- if ((unode = SCULPT_undo_get_node(node))) {
+ if ((unode = SCULPT_undo_get_node(node, type))) {
+ sculpt_undo_print_nodes(NULL);
BLI_thread_unlock(LOCK_CUSTOM1);
return unode;
}
@@ -1343,7 +1498,11 @@ SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType
int allvert;
BKE_pbvh_node_num_verts(ss->pbvh, node, NULL, &allvert);
BKE_pbvh_node_get_verts(ss->pbvh, node, &vert_indices, NULL);
- memcpy(unode->index, vert_indices, sizeof(int) * unode->totvert);
+
+ for (int i = 0; i < unode->totvert; i++) {
+ unode->index[i].i = vert_indices[i];
+ }
+ // memcpy(unode->index, vert_indices, sizeof(int) * unode->totvert);
}
switch (type) {
@@ -1380,6 +1539,8 @@ SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType
unode->shapeName[0] = '\0';
}
+ sculpt_undo_print_nodes(NULL);
+
BLI_thread_unlock(LOCK_CUSTOM1);
return unode;
@@ -1441,6 +1602,7 @@ typedef struct SculptUndoStep {
UndoStep step;
/* Note: will split out into list for multi-object-sculpt-mode. */
UndoSculpt data;
+ int id;
} SculptUndoStep;
static void sculpt_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p)
@@ -1479,6 +1641,8 @@ static void sculpt_undosys_step_decode_undo_impl(struct bContext *C,
BLI_assert(us->step.is_applied == true);
sculpt_undo_restore_list(C, depsgraph, &us->data.nodes);
us->step.is_applied = false;
+
+ sculpt_undo_print_nodes(us);
}
static void sculpt_undosys_step_decode_redo_impl(struct bContext *C,
@@ -1488,6 +1652,8 @@ static void sculpt_undosys_step_decode_redo_impl(struct bContext *C,
BLI_assert(us->step.is_applied == false);
sculpt_undo_restore_list(C, depsgraph, &us->data.nodes);
us->step.is_applied = true;
+
+ sculpt_undo_print_nodes(us);
}
static void sculpt_undosys_step_decode_undo(struct bContext *C,
@@ -1727,3 +1893,106 @@ void ED_sculpt_undo_push_multires_mesh_end(bContext *C, const char *str)
}
/** \} */
+
+#ifdef _
+# undef _
+#endif
+#define _(type) \
+ case type: \
+ return #type;
+static char *undo_type_to_str(int type)
+{
+ switch (type) {
+ _(SCULPT_UNDO_DYNTOPO_BEGIN)
+ _(SCULPT_UNDO_DYNTOPO_END)
+ _(SCULPT_UNDO_COORDS)
+ _(SCULPT_UNDO_GEOMETRY)
+ _(SCULPT_UNDO_DYNTOPO_SYMMETRIZE)
+ _(SCULPT_UNDO_FACE_SETS)
+ _(SCULPT_UNDO_HIDDEN)
+ _(SCULPT_UNDO_MASK)
+ _(SCULPT_UNDO_COLOR)
+ default:
+ return "unknown node type";
+ }
+}
+#undef _
+
+static int nodeidgen = 1;
+
+static void print_sculpt_node(SculptUndoNode *node)
+{
+ int hash = hash_sculpt_colors(node);
+
+ //if (node->lasthash == 0) {
+ // node->lasthash = hash;
+ // }
+
+ printf(" %s:%s {applied=%d gen=%d hash=%d}\n",
+ undo_type_to_str(node->type),
+ node->idname,
+ node->applied,
+ 0, //node->gen,
+ hash /*- node->lasthash*/);
+}
+
+static void print_sculpt_undo_step(UndoStep *us, UndoStep *active, int i)
+{
+ SculptUndoNode *node;
+
+ if (us->type != BKE_UNDOSYS_TYPE_SCULPT) {
+ return;
+ }
+
+ int id = -1;
+
+ SculptUndoStep *su = (SculptUndoStep *)us;
+ if (!su->id) {
+ su->id = nodeidgen++;
+ }
+
+ id = su->id;
+
+ printf("id=%d %s %d %s\n", id, us == active ? "->" : " ", i, us->name);
+
+ if (us->type == BKE_UNDOSYS_TYPE_SCULPT) {
+ UndoSculpt *usculpt = sculpt_undosys_step_get_nodes(us);
+
+ for (node = usculpt->nodes.first; node; node = node->next) {
+ print_sculpt_node(node);
+ }
+ }
+}
+void sculpt_undo_print_nodes(void *active)
+{
+#if 0
+ UndoStack *ustack = ED_undo_stack_get();
+ UndoStep *us = ustack->steps.first;
+ if (active == NULL) {
+ active = ustack->step_active;
+ }
+
+ SculptUndoNode *node;
+
+ if (!us) {
+ return;
+ }
+
+ printf("\n");
+ if (ustack->step_init) {
+ printf("===undo init===\n");
+ print_sculpt_undo_step(ustack->step_init, active, -1);
+ printf("===============\n");
+ }
+
+ int i = 0;
+ for (; us; us = us->next, i++) {
+ print_sculpt_undo_step(us, active, i);
+ }
+
+ if (ustack->step_active) {
+ print_sculpt_undo_step(ustack->step_active, active, i);
+ }
+
+#endif
+}
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index fc5f41e8ed5..42a54010ceb 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -2860,7 +2860,8 @@ void ED_uvedit_add_simple_uvs(Main *bmain, const Scene *scene, Object *ob)
ED_mesh_uv_texture_ensure(me, NULL);
- BM_mesh_bm_from_me(bm,
+ BM_mesh_bm_from_me(NULL,
+ bm,
me,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
@@ -2871,7 +2872,7 @@ void ED_uvedit_add_simple_uvs(Main *bmain, const Scene *scene, Object *ob)
/* set the margin really quickly before the packing operation*/
scene->toolsettings->uvcalc_margin = 0.001f;
uvedit_pack_islands(scene, ob, bm);
- BM_mesh_bm_to_me(bmain, bm, me, (&(struct BMeshToMeshParams){0}));
+ BM_mesh_bm_to_me(bmain, NULL, bm, me, (&(struct BMeshToMeshParams){0}));
BM_mesh_free(bm);
if (sync_selection) {
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index b770bde65fc..50262148eb1 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -34,6 +34,7 @@ struct CCGElem;
struct CCGKey;
struct DMFlagMat;
struct GSet;
+struct TableGSet;
struct MLoop;
struct MLoopCol;
struct MLoopTri;
@@ -43,6 +44,7 @@ struct MVert;
struct Mesh;
struct PBVH;
struct SubdivCCG;
+struct CustomData;
/* Buffers for drawing from PBVH grids. */
typedef struct GPU_PBVH_Buffers GPU_PBVH_Buffers;
@@ -85,12 +87,17 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const struct MPropCol *vtcol,
const int update_flags);
+void GPU_pbvh_update_attribute_names(struct CustomData *vdata, struct CustomData *ldata);
void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
struct BMesh *bm,
- struct GSet *bm_faces,
- struct GSet *bm_unique_verts,
- struct GSet *bm_other_verts,
- const int update_flags);
+ struct TableGSet *bm_faces,
+ struct TableGSet *bm_unique_verts,
+ struct TableGSet *bm_other_verts,
+ const int update_flags,
+ const int cd_vert_node_offset,
+ int face_sets_color_seed,
+ int face_sets_color_default,
+ bool flat_vcol);
void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
struct SubdivCCG *subdiv_ccg,
diff --git a/source/blender/gpu/GPU_vertex_format.h b/source/blender/gpu/GPU_vertex_format.h
index e3a566e5f21..84b43d8060b 100644
--- a/source/blender/gpu/GPU_vertex_format.h
+++ b/source/blender/gpu/GPU_vertex_format.h
@@ -112,6 +112,8 @@ void GPU_vertformat_from_shader(GPUVertFormat *format, const struct GPUShader *s
uint GPU_vertformat_attr_add(
GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode);
void GPU_vertformat_alias_add(GPUVertFormat *, const char *alias);
+void GPU_vertformat_alias_clear(GPUVertFormat *format, int attr_id);
+void GPU_vertformat_alias_add_n(GPUVertFormat *format, int attr_id, const char *alias);
void GPU_vertformat_multiload_enable(GPUVertFormat *format, int load_count);
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 13d0139e406..3cf7079560d 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -42,6 +42,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_ccg.h"
+#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
@@ -50,6 +51,8 @@
#include "GPU_batch.h"
#include "GPU_buffers.h"
+#include "DRW_engine.h"
+
#include "gpu_private.h"
#include "bmesh.h"
@@ -100,7 +103,7 @@ struct GPU_PBVH_Buffers {
static struct {
GPUVertFormat format;
- uint pos, nor, msk, col, fset;
+ uint pos, nor, msk, col, fset, uv;
} g_vbo_id = {{0}};
/** \} */
@@ -111,20 +114,7 @@ static struct {
void gpu_pbvh_init()
{
- /* Initialize vertex buffer (match 'VertexBufferFormat'). */
- if (g_vbo_id.format.attr_len == 0) {
- g_vbo_id.pos = GPU_vertformat_attr_add(
- &g_vbo_id.format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- g_vbo_id.nor = GPU_vertformat_attr_add(
- &g_vbo_id.format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
- /* TODO: Do not allocate these `.msk` and `.col` when they are not used. */
- g_vbo_id.msk = GPU_vertformat_attr_add(
- &g_vbo_id.format, "msk", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
- g_vbo_id.col = GPU_vertformat_attr_add(
- &g_vbo_id.format, "ac", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- g_vbo_id.fset = GPU_vertformat_attr_add(
- &g_vbo_id.format, "fset", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
- }
+ GPU_pbvh_update_attribute_names(NULL, NULL);
}
void gpu_pbvh_exit()
@@ -787,15 +777,17 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, BLI_bitmap **grid_hid
* \{ */
/* Output a BMVert into a VertexBufferFormat array at v_index. */
-static void gpu_bmesh_vert_to_buffer_copy(BMVert *v,
+__attribute__((optnone)) static void gpu_bmesh_vert_to_buffer_copy(BMVert *v,
GPUVertBuf *vert_buf,
int v_index,
const float fno[3],
const float *fmask,
const int cd_vert_mask_offset,
+ const int cd_vert_node_offset,
const bool show_mask,
const bool show_vcol,
- bool *empty_mask)
+ bool *empty_mask,
+ int cd_vcol_offset)
{
/* Vertex should always be visible if it's used by a visible face. */
BLI_assert(!BM_elem_flag_test(v, BM_ELEM_HIDDEN));
@@ -809,14 +801,54 @@ static void gpu_bmesh_vert_to_buffer_copy(BMVert *v,
if (show_mask) {
float effective_mask = fmask ? *fmask : BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset);
+
+ if (G.debug_value == 889) {
+ int ni = BM_ELEM_CD_GET_INT(v, cd_vert_node_offset);
+
+ effective_mask = ni == -1 ? 0.0f : (float)((ni * 50) % 32) / 32.0f;
+ }
+
uchar cmask = (uchar)(effective_mask * 255);
GPU_vertbuf_attr_set(vert_buf, g_vbo_id.msk, v_index, &cmask);
*empty_mask = *empty_mask && (cmask == 0);
}
- if (show_vcol) {
+ if (show_vcol && cd_vcol_offset >= 0) {
+ ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
+ int col[4] = {0, 0, 0, 0};
+ int tot = 0;
+
+ BMIter iter;
+ BMLoop *l;
+
+ BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
+ MLoopCol *ml = BM_ELEM_CD_GET_VOID_P(l, cd_vcol_offset);
+
+ col[0] += ml->r;
+ col[1] += ml->g;
+ col[2] += ml->b;
+ col[3] += ml->a;
+ tot++;
+ }
+
+ if (tot) {
+ col[0] /= tot;
+ col[1] /= tot;
+ col[2] /= tot;
+ col[3] /= tot;
+
+ vcol[0] = (ushort)(col[0] * 257);
+ vcol[1] = (ushort)(col[1] * 257);
+ vcol[2] = (ushort)(col[2] * 257);
+ vcol[3] = (ushort)(col[3] * 257);
+ // printf("%d %d %d %d %d\n", vcol[0], vcol[1], vcol[2], vcol[3], tot);
+ }
+ // const ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
+ GPU_vertbuf_attr_set(vert_buf, g_vbo_id.col, v_index, vcol);
+ }
+ else if (show_vcol) {
const ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
- GPU_vertbuf_attr_set(vert_buf, g_vbo_id.col, v_index, &vcol);
+ GPU_vertbuf_attr_set(vert_buf, g_vbo_id.col, v_index, vcol);
}
/* Add default face sets color to avoid artifacts. */
@@ -825,40 +857,40 @@ static void gpu_bmesh_vert_to_buffer_copy(BMVert *v,
}
/* Return the total number of vertices that don't have BM_ELEM_HIDDEN set */
-static int gpu_bmesh_vert_visible_count(GSet *bm_unique_verts, GSet *bm_other_verts)
+static int gpu_bmesh_vert_visible_count(TableGSet *bm_unique_verts, TableGSet *bm_other_verts)
{
- GSetIterator gs_iter;
int totvert = 0;
+ BMVert *v;
- GSET_ITER (gs_iter, bm_unique_verts) {
- BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
+ TGSET_ITER (v, bm_unique_verts) {
if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
totvert++;
}
}
- GSET_ITER (gs_iter, bm_other_verts) {
- BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
+ TGSET_ITER_END
+
+ TGSET_ITER (v, bm_other_verts) {
if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
totvert++;
}
}
+ TGSET_ITER_END
return totvert;
}
/* Return the total number of visible faces */
-static int gpu_bmesh_face_visible_count(GSet *bm_faces)
+static int gpu_bmesh_face_visible_count(TableGSet *bm_faces)
{
- GSetIterator gh_iter;
int totface = 0;
+ BMFace *f;
- GSET_ITER (gh_iter, bm_faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gh_iter);
-
+ TGSET_ITER (f, bm_faces) {
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
totface++;
}
}
+ TGSET_ITER_END
return totface;
}
@@ -878,25 +910,290 @@ void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers)
}
}
+void GPU_pbvh_update_attribute_names(CustomData *vdata, CustomData *ldata)
+{
+ GPU_vertformat_clear(&g_vbo_id);
+
+ /* Initialize vertex buffer (match 'VertexBufferFormat'). */
+ if (g_vbo_id.format.attr_len == 0) {
+ g_vbo_id.pos = GPU_vertformat_attr_add(
+ &g_vbo_id.format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ g_vbo_id.nor = GPU_vertformat_attr_add(
+ &g_vbo_id.format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ /* TODO: Do not allocate these `.msk` and `.col` when they are not used. */
+ g_vbo_id.msk = GPU_vertformat_attr_add(
+ &g_vbo_id.format, "msk", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ g_vbo_id.col = GPU_vertformat_attr_add(
+ &g_vbo_id.format, "c", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ if (vdata && CustomData_has_layer(vdata, CD_PROP_COLOR)) {
+ const int cd_vcol_index = CustomData_get_layer_index(vdata, CD_PROP_COLOR);
+ CustomDataLayer *cl = vdata->layers + cd_vcol_index;
+ cl += cl->active;
+
+ DRW_make_cdlayer_attr_aliases(&g_vbo_id.format, "c", vdata, cl);
+ GPU_vertformat_alias_add(&g_vbo_id.format, "ac");
+ }
+
+ g_vbo_id.fset = GPU_vertformat_attr_add(
+ &g_vbo_id.format, "fset", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ g_vbo_id.uv = GPU_vertformat_attr_add(
+ &g_vbo_id.format, "uvs", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ GPU_vertformat_alias_add(&g_vbo_id.format, "u");
+
+ if (ldata && CustomData_has_layer(ldata, CD_MLOOPUV)) {
+ const int cd_uv_index = CustomData_get_layer_index(ldata, CD_MLOOPUV);
+ CustomDataLayer *cl = ldata->layers + cd_uv_index;
+ cl += cl->active;
+
+ DRW_make_cdlayer_attr_aliases(&g_vbo_id.format, "u", ldata, cl);
+ }
+ }
+}
+
+static void gpu_flat_vcol_make_vert(float co[3],
+ BMVert *v,
+ GPUVertBuf *vert_buf,
+ int v_index,
+ int cd_vcol_offset,
+ const float fno[3])
+{
+ MPropCol *mp = BM_ELEM_CD_GET_VOID_P(v, cd_vcol_offset);
+ ushort vcol[4];
+
+ // printf(
+ // "%.2f %.2f %.2f %.2f\n", mp->color[0], mp->color[1], mp->color[2], mp->color[3]);
+ vcol[0] = unit_float_to_ushort_clamp(mp->color[0]);
+ vcol[1] = unit_float_to_ushort_clamp(mp->color[1]);
+ vcol[2] = unit_float_to_ushort_clamp(mp->color[2]);
+ vcol[3] = unit_float_to_ushort_clamp(mp->color[3]);
+
+ GPU_vertbuf_attr_set(vert_buf, g_vbo_id.col, v_index, vcol);
+
+ /* Set coord, normal, and mask */
+ GPU_vertbuf_attr_set(vert_buf, g_vbo_id.pos, v_index, co);
+
+ short no_short[3];
+
+ normal_float_to_short_v3(no_short, fno ? fno : v->no);
+ GPU_vertbuf_attr_set(vert_buf, g_vbo_id.nor, v_index, no_short);
+}
+
+/* Creates a vertex buffer (coordinate, normal, color) and, if smooth
+ * shading, an element index buffer.
+ * Threaded - do not call any functions that use OpenGL calls! */
+static void GPU_pbvh_bmesh_buffers_update_flat_vcol(GPU_PBVH_Buffers *buffers,
+ BMesh *bm,
+ TableGSet *bm_faces,
+ TableGSet *bm_unique_verts,
+ TableGSet *bm_other_verts,
+ const int update_flags,
+ const int cd_vert_node_offset,
+ int face_sets_color_seed,
+ int face_sets_color_default)
+{
+ const bool have_uv = CustomData_has_layer(&bm->ldata, CD_MLOOPUV);
+ const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
+ const bool show_vcol = (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0;
+ const bool show_face_sets = CustomData_has_layer(&bm->pdata, CD_SCULPT_FACE_SETS) &&
+ (update_flags & GPU_PBVH_BUFFERS_SHOW_SCULPT_FACE_SETS) != 0;
+
+ int tottri, totvert;
+ bool empty_mask = true;
+ BMFace *f = NULL;
+ int cd_vcol_offset = CustomData_get_offset(&bm->vdata, CD_PROP_COLOR);
+ int cd_fset_offset = CustomData_get_offset(&bm->pdata, CD_SCULPT_FACE_SETS);
+
+ /* Count visible triangles */
+ tottri = gpu_bmesh_face_visible_count(bm_faces) * 6;
+
+ // XXX disable indexed verts for now
+ totvert = tottri * 3;
+
+ if (!tottri) {
+ if (BLI_table_gset_len(bm_faces) != 0) {
+ /* Node is just hidden. */
+ }
+ else {
+ buffers->clear_bmesh_on_flush = true;
+ }
+ buffers->tot_tri = 0;
+ return;
+ }
+
+ /* TODO, make mask layer optional for bmesh buffer */
+ const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
+ const int cd_mcol_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL);
+ const int cd_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ bool default_face_set = true;
+
+ /* Fill vertex buffer */
+ if (!gpu_pbvh_vert_buf_data_set(buffers, totvert)) {
+ /* Memory map failed */
+ return;
+ }
+
+ int v_index = 0;
+
+ // disable shared vertex mode for now
+
+ GPUIndexBufBuilder elb_lines;
+ GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, tottri * 3);
+
+ TGSET_ITER (f, bm_faces) {
+ BLI_assert(f->len == 3);
+
+ if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ BMVert *v[3];
+ BMLoop *l[3] = {f->l_first, f->l_first->next, f->l_first->prev};
+
+ float fmask = 0.0f;
+ int i;
+
+ BM_face_as_array_vert_tri(f, v);
+
+ /* Average mask value */
+ for (i = 0; i < 3; i++) {
+ fmask += BM_ELEM_CD_GET_FLOAT(v[i], cd_vert_mask_offset);
+ }
+ fmask /= 3.0f;
+
+ /*
+
+
+ v1
+ |\
+ | \
+ v3 v4
+ | v6 \
+ | \
+ v0---v5---v2
+ */
+ GPU_indexbuf_add_line_verts(&elb_lines, v_index + 0, v_index + 1);
+ GPU_indexbuf_add_line_verts(&elb_lines, v_index + 1, v_index + 2);
+ GPU_indexbuf_add_line_verts(&elb_lines, v_index + 2, v_index + 0);
+
+ uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
+
+ if (show_face_sets && cd_fset_offset >= 0) {
+ const int fset = BM_ELEM_CD_GET_INT(f, cd_fset_offset);
+
+ /* Skip for the default color Face Set to render it white. */
+ if (fset != face_sets_color_default) {
+ BKE_paint_face_set_overlay_color_get(fset, face_sets_color_seed, face_set_color);
+ default_face_set = false;
+ }
+ }
+
+ float cent[3] = {0.0f, 0.0f, 0.0f};
+ add_v3_v3(cent, v[0]->co);
+ add_v3_v3(cent, v[1]->co);
+ add_v3_v3(cent, v[2]->co);
+ mul_v3_fl(cent, 1.0 / 3.0);
+
+ float *cos[7][3];
+
+ copy_v3_v3(cos[0], v[0]->co);
+ copy_v3_v3(cos[1], v[1]->co);
+ copy_v3_v3(cos[2], v[2]->co);
+
+ float v3[3];
+ float v4[3];
+ float v5[3];
+ float v6[3];
+
+ copy_v3_v3(cos[6], cent);
+
+ interp_v3_v3v3(cos[3], v[0]->co, v[1]->co, 0.5f);
+ interp_v3_v3v3(cos[4], v[1]->co, v[2]->co, 0.5f);
+ interp_v3_v3v3(cos[5], v[2]->co, v[0]->co, 0.5f);
+
+ for (int j = 0; j < 3; j++) {
+ int next = 3 + ((j) % 3);
+ int prev = 3 + ((j + 3 - 1) % 3);
+
+ gpu_flat_vcol_make_vert(v[j]->co, v[j], buffers->vert_buf, v_index, cd_vcol_offset, f->no);
+ gpu_flat_vcol_make_vert(
+ cos[next], v[j], buffers->vert_buf, v_index + 1, cd_vcol_offset, f->no);
+ gpu_flat_vcol_make_vert(
+ cos[6], v[j], buffers->vert_buf, v_index + 2, cd_vcol_offset, f->no);
+
+ gpu_flat_vcol_make_vert(
+ v[j]->co, v[j], buffers->vert_buf, v_index + 3, cd_vcol_offset, f->no);
+ gpu_flat_vcol_make_vert(
+ cos[6], v[j], buffers->vert_buf, v_index + 4, cd_vcol_offset, f->no);
+ gpu_flat_vcol_make_vert(
+ cos[prev], v[j], buffers->vert_buf, v_index + 5, cd_vcol_offset, f->no);
+
+ v_index += 6;
+ }
+ /*
+ if (have_uv) {
+ MLoopUV *mu = BM_ELEM_CD_GET_VOID_P(l[i], cd_uv_offset);
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.uv, v_index, mu->uv);
+ }
+ */
+ }
+ }
+ TGSET_ITER_END
+
+ buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines);
+ buffers->tot_tri = tottri;
+
+ /* Get material index from the last face we iterated on. */
+ buffers->material_index = (f) ? f->mat_nr : 0;
+
+ buffers->show_overlay = !empty_mask || !default_face_set;
+
+ gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS);
+}
+
/* Creates a vertex buffer (coordinate, normal, color) and, if smooth
* shading, an element index buffer.
* Threaded - do not call any functions that use OpenGL calls! */
void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
BMesh *bm,
- GSet *bm_faces,
- GSet *bm_unique_verts,
- GSet *bm_other_verts,
- const int update_flags)
+ TableGSet *bm_faces,
+ TableGSet *bm_unique_verts,
+ TableGSet *bm_other_verts,
+ const int update_flags,
+ const int cd_vert_node_offset,
+ int face_sets_color_seed,
+ int face_sets_color_default,
+ bool flat_vcol)
{
+
+ if (flat_vcol && CustomData_has_layer(&bm->vdata, CD_PROP_COLOR)) {
+ GPU_pbvh_bmesh_buffers_update_flat_vcol(buffers,
+ bm,
+ bm_faces,
+ bm_unique_verts,
+ bm_other_verts,
+ update_flags,
+ cd_vert_node_offset,
+ face_sets_color_seed,
+ face_sets_color_default);
+ return;
+ }
+
+ const bool have_uv = CustomData_has_layer(&bm->ldata, CD_MLOOPUV);
const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
const bool show_vcol = (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0;
+ const bool show_face_sets = CustomData_has_layer(&bm->pdata, CD_SCULPT_FACE_SETS) &&
+ (update_flags & GPU_PBVH_BUFFERS_SHOW_SCULPT_FACE_SETS) != 0;
+
int tottri, totvert;
bool empty_mask = true;
BMFace *f = NULL;
+ int cd_vcol_offset = CustomData_get_offset(&bm->vdata, CD_PROP_COLOR);
+ int cd_fset_offset = CustomData_get_offset(&bm->pdata, CD_SCULPT_FACE_SETS);
/* Count visible triangles */
tottri = gpu_bmesh_face_visible_count(bm_faces);
+ // XXX disable indexed verts for now
if (buffers->smooth) {
/* Count visible vertices */
totvert = gpu_bmesh_vert_visible_count(bm_unique_verts, bm_other_verts);
@@ -906,7 +1203,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
}
if (!tottri) {
- if (BLI_gset_len(bm_faces) != 0) {
+ if (BLI_table_gset_len(bm_faces) != 0) {
/* Node is just hidden. */
}
else {
@@ -918,6 +1215,10 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
/* TODO, make mask layer optional for bmesh buffer */
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
+ const int cd_mcol_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL);
+ const int cd_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ bool default_face_set = true;
/* Fill vertex buffer */
if (!gpu_pbvh_vert_buf_data_set(buffers, totvert)) {
@@ -927,6 +1228,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
int v_index = 0;
+ // disable shared vertex mode for now
if (buffers->smooth) {
/* Fill the vertex and triangle buffer in one pass over faces. */
GPUIndexBufBuilder elb, elb_lines;
@@ -934,11 +1236,9 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, totvert);
GHash *bm_vert_to_index = BLI_ghash_int_new_ex("bm_vert_to_index", totvert);
+ BMFace *f;
- GSetIterator gs_iter;
- GSET_ITER (gs_iter, bm_faces) {
- f = BLI_gsetIterator_getKey(&gs_iter);
-
+ TGSET_ITER (f, bm_faces) {
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
BMVert *v[3];
BM_face_as_array_vert_tri(f, v);
@@ -956,9 +1256,11 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
NULL,
NULL,
cd_vert_mask_offset,
+ cd_vert_node_offset,
show_mask,
show_vcol,
- &empty_mask);
+ &empty_mask,
+ cd_mcol_offset);
idx[i] = v_index;
v_index++;
@@ -976,6 +1278,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
GPU_indexbuf_add_line_verts(&elb_lines, idx[2], idx[0]);
}
}
+ TGSET_ITER_END
BLI_ghash_free(bm_vert_to_index, NULL, NULL);
@@ -989,18 +1292,17 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines);
}
else {
- GSetIterator gs_iter;
-
GPUIndexBufBuilder elb_lines;
GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, tottri * 3);
+ BMFace *f;
- GSET_ITER (gs_iter, bm_faces) {
- f = BLI_gsetIterator_getKey(&gs_iter);
-
+ TGSET_ITER (f, bm_faces) {
BLI_assert(f->len == 3);
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
BMVert *v[3];
+ BMLoop *l[3] = {f->l_first, f->l_first->next, f->l_first->prev};
+
float fmask = 0.0f;
int i;
@@ -1016,19 +1318,71 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
GPU_indexbuf_add_line_verts(&elb_lines, v_index + 1, v_index + 2);
GPU_indexbuf_add_line_verts(&elb_lines, v_index + 2, v_index + 0);
+ uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
+
+ if (show_face_sets && cd_fset_offset >= 0) {
+ const int fset = BM_ELEM_CD_GET_INT(f, cd_fset_offset);
+
+ /* Skip for the default color Face Set to render it white. */
+ if (fset != face_sets_color_default) {
+ BKE_paint_face_set_overlay_color_get(fset, face_sets_color_seed, face_set_color);
+ default_face_set = false;
+ }
+ }
+
for (i = 0; i < 3; i++) {
+ float *no = buffers->smooth ? v[i]->no : f->no;
+
gpu_bmesh_vert_to_buffer_copy(v[i],
buffers->vert_buf,
- v_index++,
- f->no,
+ v_index,
+ no,
&fmask,
cd_vert_mask_offset,
+ cd_vert_node_offset,
show_mask,
- show_vcol,
- &empty_mask);
+ false,
+ &empty_mask,
+ -1);
+
+ if (cd_vcol_offset >= 0) {
+ MPropCol *mp = BM_ELEM_CD_GET_VOID_P(l[i]->v, cd_vcol_offset);
+ ushort vcol[4];
+
+ // printf(
+ // "%.2f %.2f %.2f %.2f\n", mp->color[0], mp->color[1], mp->color[2], mp->color[3]);
+ vcol[0] = unit_float_to_ushort_clamp(mp->color[0]);
+ vcol[1] = unit_float_to_ushort_clamp(mp->color[1]);
+ vcol[2] = unit_float_to_ushort_clamp(mp->color[2]);
+ vcol[3] = unit_float_to_ushort_clamp(mp->color[3]);
+
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, v_index, vcol);
+ }
+ else if (cd_mcol_offset >= 0) {
+ ushort vcol[4];
+
+ MLoopCol *ml = BM_ELEM_CD_GET_VOID_P(l[i], cd_mcol_offset);
+
+ vcol[0] = ml->r * 257;
+ vcol[1] = ml->g * 257;
+ vcol[2] = ml->b * 257;
+ vcol[3] = ml->a * 257;
+
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, v_index, vcol);
+ }
+
+ if (have_uv) {
+ MLoopUV *mu = BM_ELEM_CD_GET_VOID_P(l[i], cd_uv_offset);
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.uv, v_index, mu->uv);
+ }
+
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, v_index, face_set_color);
+
+ v_index++;
}
}
}
+ TGSET_ITER_END
buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines);
buffers->tot_tri = tottri;
@@ -1037,13 +1391,11 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
/* Get material index from the last face we iterated on. */
buffers->material_index = (f) ? f->mat_nr : 0;
- buffers->show_overlay = !empty_mask;
+ buffers->show_overlay = !empty_mask || !default_face_set;
gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS);
}
-/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Generic
* \{ */
diff --git a/source/blender/io/alembic/exporter/abc_writer_mesh.cc b/source/blender/io/alembic/exporter/abc_writer_mesh.cc
index fbc662113cc..151792f5ed6 100644
--- a/source/blender/io/alembic/exporter/abc_writer_mesh.cc
+++ b/source/blender/io/alembic/exporter/abc_writer_mesh.cc
@@ -189,7 +189,7 @@ void ABCGenericMeshWriter::do_write(HierarchyContext &context)
struct BMeshCreateParams bmcp = {false};
struct BMeshFromMeshParams bmfmp = {true, false, false, 0};
- BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmcp, &bmfmp);
+ BMesh *bm = BKE_mesh_to_bmesh_ex(object, mesh, &bmcp, &bmfmp);
BM_mesh_triangulate(bm, quad_method, ngon_method, 4, tag_only, nullptr, nullptr, nullptr);
diff --git a/source/blender/io/collada/collada_utils.cpp b/source/blender/io/collada/collada_utils.cpp
index bba50064879..ceeffe070df 100644
--- a/source/blender/io/collada/collada_utils.cpp
+++ b/source/blender/io/collada/collada_utils.cpp
@@ -448,12 +448,12 @@ void bc_triangulate_mesh(Mesh *me)
BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default, &bm_create_params);
BMeshFromMeshParams bm_from_me_params = {0};
bm_from_me_params.calc_face_normal = true;
- BM_mesh_bm_from_me(bm, me, &bm_from_me_params);
+ BM_mesh_bm_from_me(nullptr, bm, me, &bm_from_me_params);
BM_mesh_triangulate(bm, quad_method, use_beauty, 4, tag_only, nullptr, nullptr, nullptr);
BMeshToMeshParams bm_to_me_params = {0};
bm_to_me_params.calc_object_remap = false;
- BM_mesh_bm_to_me(nullptr, bm, me, &bm_to_me_params);
+ BM_mesh_bm_to_me(nullptr, nullptr, bm, me, &bm_to_me_params);
BM_mesh_free(bm);
}
diff --git a/source/blender/makesdna/DNA_brush_enums.h b/source/blender/makesdna/DNA_brush_enums.h
index 093a1a00ece..396d248014d 100644
--- a/source/blender/makesdna/DNA_brush_enums.h
+++ b/source/blender/makesdna/DNA_brush_enums.h
@@ -328,6 +328,8 @@ typedef enum eAutomasking_flag {
BRUSH_AUTOMASKING_FACE_SETS = (1 << 1),
BRUSH_AUTOMASKING_BOUNDARY_EDGES = (1 << 2),
BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS = (1 << 3),
+ BRUSH_AUTOMASKING_CONCAVITY = (1 << 4),
+ BRUSH_AUTOMASKING_INVERT_CONCAVITY = (1<<5)
} eAutomasking_flag;
typedef enum ePaintBrush_flag {
@@ -462,6 +464,7 @@ typedef enum eBrushSculptTool {
SCULPT_TOOL_BOUNDARY = 30,
SCULPT_TOOL_DISPLACEMENT_ERASER = 31,
SCULPT_TOOL_DISPLACEMENT_SMEAR = 32,
+ SCULPT_TOOL_VCOL_BOUNDARY = 33,
} eBrushSculptTool;
/* Brush.uv_sculpt_tool */
@@ -471,6 +474,11 @@ typedef enum eBrushUVSculptTool {
UV_SCULPT_TOOL_PINCH = 2,
} eBrushUVSculptTool;
+#define SCULPT_TOOL_HAS_VCOL_BOUNDARY_SMOOTH(t) \
+ ELEM(t, \
+ SCULPT_TOOL_PAINT,\
+ SCULPT_TOOL_SMEAR)
+
/** When #BRUSH_ACCUMULATE is used */
#define SCULPT_TOOL_HAS_ACCUMULATE(t) \
ELEM(t, \
@@ -500,7 +508,6 @@ typedef enum eBrushUVSculptTool {
SCULPT_TOOL_THUMB, \
SCULPT_TOOL_LAYER, \
SCULPT_TOOL_DISPLACEMENT_ERASER, \
- SCULPT_TOOL_DRAW_SHARP, \
SCULPT_TOOL_SLIDE_RELAX, \
SCULPT_TOOL_ELASTIC_DEFORM, \
SCULPT_TOOL_BOUNDARY, \
@@ -512,6 +519,7 @@ typedef enum eBrushUVSculptTool {
/* These brushes could handle dynamic topology, \ \
* but user feedback indicates it's better not to */ \
SCULPT_TOOL_SMOOTH, \
+ SCULPT_TOOL_VCOL_BOUNDARY, \
SCULPT_TOOL_MASK) == 0)
#define SCULPT_TOOL_HAS_TOPOLOGY_RAKE(t) \
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index a11e7d77c67..ab636623390 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -243,7 +243,7 @@ typedef struct Brush {
/** Source for fill tool color gradient application. */
char gradient_fill_mode;
- char _pad0[5];
+ char _pad0[1];
/** Projection shape (sphere, circle). */
char falloff_shape;
@@ -276,6 +276,8 @@ typedef struct Brush {
float tilt_strength_factor;
float topology_rake_factor;
+ float vcol_boundary_factor;
+ float vcol_boundary_exponent;
float crease_pinch_factor;
@@ -370,8 +372,8 @@ typedef struct Brush {
float mask_stencil_pos[2];
float mask_stencil_dimension[2];
+ float concave_mask_factor;
struct BrushGpencilSettings *gpencil_settings;
-
} Brush;
/* Struct to hold palette colors for sorting. */
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index dbcb6ce45ea..c5e2397b995 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -1899,6 +1899,7 @@ typedef struct UVWarpModifierData {
/* UVWarp modifier flags */
enum {
MOD_UVWARP_INVERT_VGROUP = 1 << 0,
+ MOD_UVWARP_RESTRICT_ISLANDS = 1<<1
};
/* cache modifier */
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index c7f7e610a1a..97914e6cc06 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -2214,6 +2214,7 @@ typedef enum eSculptFlags {
/* Don't display face sets in viewport. */
SCULPT_HIDE_FACE_SETS = (1 << 17),
+ SCULPT_DYNTOPO_FLAT_VCOL_SHADING = (1<<18)
} eSculptFlags;
/** #ImagePaintSettings.mode */
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index e7daa55af6c..d603fea5a4a 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -135,10 +135,11 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = {
{SCULPT_TOOL_MASK, "MASK", ICON_BRUSH_MASK, "Mask", ""},
{SCULPT_TOOL_DISPLACEMENT_ERASER, "DISPLACEMENT_ERASER", ICON_BRUSH_SCULPT_DRAW, "Multires Displacement Eraser", ""},
{SCULPT_TOOL_DISPLACEMENT_SMEAR, "DISPLACEMENT_SMEAR", ICON_BRUSH_SCULPT_DRAW, "Multires Displacement Smear", ""},
- {SCULPT_TOOL_PAINT, "PAINT", ICON_BRUSH_SCULPT_DRAW, "Paint", ""},
+ {SCULPT_TOOL_PAINT, "PAINT", ICON_BRUSH_PAINT, "Paint", ""},
{SCULPT_TOOL_SMEAR, "SMEAR", ICON_BRUSH_SCULPT_DRAW, "Smear", ""},
{SCULPT_TOOL_DRAW_FACE_SETS, "DRAW_FACE_SETS", ICON_BRUSH_MASK, "Draw Face Sets", ""},
- {0, NULL, 0, NULL, NULL},
+ {SCULPT_TOOL_VCOL_BOUNDARY, "VCOL_BOUNDARY", ICON_BRUSH_VCOL_BOUNDARY, "Sharpen Color Boundary", ""},
+ {0, NULL, 0, NULL, NULL},
};
/* clang-format on */
@@ -370,6 +371,12 @@ static bool rna_BrushCapabilitiesSculpt_has_topology_rake_get(PointerRNA *ptr)
return SCULPT_TOOL_HAS_TOPOLOGY_RAKE(br->sculpt_tool);
}
+static bool rna_BrushCapabilitiesSculpt_has_vcol_boundary_smooth_get(PointerRNA *ptr)
+{
+ Brush *br = (Brush *)ptr->data;
+ return SCULPT_TOOL_HAS_VCOL_BOUNDARY_SMOOTH(br->sculpt_tool);
+}
+
static bool rna_BrushCapabilitiesSculpt_has_auto_smooth_get(PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
@@ -1150,6 +1157,7 @@ static void rna_def_sculpt_capabilities(BlenderRNA *brna)
SCULPT_TOOL_CAPABILITY(has_accumulate, "Has Accumulate");
SCULPT_TOOL_CAPABILITY(has_auto_smooth, "Has Auto Smooth");
SCULPT_TOOL_CAPABILITY(has_topology_rake, "Has Topology Rake");
+ SCULPT_TOOL_CAPABILITY(has_vcol_boundary_smooth, "Has VCol Boundary Smooth");
SCULPT_TOOL_CAPABILITY(has_height, "Has Height");
SCULPT_TOOL_CAPABILITY(has_jitter, "Has Jitter");
SCULPT_TOOL_CAPABILITY(has_normal_weight, "Has Crease/Pinch Factor");
@@ -2856,6 +2864,15 @@ static void rna_def_brush(BlenderRNA *brna)
prop, "Auto-Smooth", "Amount of smoothing to automatically apply to each stroke");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "concave_mask_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "concave_mask_factor");
+ RNA_def_property_float_default(prop, 0);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 3);
+ RNA_def_property_ui_text(
+ prop, "Cavity Mask", "Mask to concave areas");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "topology_rake_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "topology_rake_factor");
RNA_def_property_float_default(prop, 0);
@@ -2868,6 +2885,27 @@ static void rna_def_brush(BlenderRNA *brna)
"Best used on low-poly meshes as it has a performance impact");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "vcol_boundary_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "vcol_boundary_factor");
+ RNA_def_property_float_default(prop, 0);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 3);
+ RNA_def_property_ui_text(prop,
+ "Boundary Hardening",
+ "Automatically align edges on color boundaries"
+ "to generate sharper features. ");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop = RNA_def_property(srna, "vcol_boundary_exponent", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "vcol_boundary_exponent");
+ RNA_def_property_float_default(prop, 0);
+ RNA_def_property_range(prop, 0.0f, 6.0f);
+ RNA_def_property_ui_range(prop, 0.1f, 3.0f, 0.001, 3);
+ RNA_def_property_ui_text(prop,
+ "Exponent",
+ "Hardening exponent (smaller value smoother edges)");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "tilt_strength_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "tilt_strength_factor");
RNA_def_property_float_default(prop, 0);
@@ -2992,6 +3030,16 @@ static void rna_def_brush(BlenderRNA *brna)
"When locked keep using the plane origin of surface where stroke was initiated");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ //note that concavity flag is derived from brush->concave_mask_factor being nonzero,
+ //so we just expose the invert concave flag here
+ prop = RNA_def_property(srna, "invert_automasking_concavity", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_INVERT_CONCAVITY);
+ RNA_def_property_ui_text(prop,
+ "Invert Cavity Mask",
+ "Invert mask to expose convex instead of concave areas");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "use_automasking_topology", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_TOPOLOGY);
RNA_def_property_ui_text(prop,
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 5008240ea33..2635d8b9669 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -4975,6 +4975,13 @@ static void rna_def_modifier_uvwarp(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "restrict_to_islands", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_UVWARP_RESTRICT_ISLANDS);
+ RNA_def_property_ui_text(prop,
+ "Island Restrict",
+ "Don't affect UVs in faces outside of the vertex group's influence");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "uv_layer", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "uvlayer_name");
RNA_def_property_ui_text(prop, "UV Layer", "UV Layer name");
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 4481555b931..166d03367c2 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -368,6 +368,8 @@ static bool rna_Brush_mode_with_tool_poll(PointerRNA *ptr, PointerRNA value)
return brush->ob_mode & mode;
}
+void SCULPT_update_flat_vcol_shading(Object *ob, Scene *scene);
+
static void rna_Sculpt_update(bContext *C, PointerRNA *UNUSED(ptr))
{
Scene *scene = CTX_data_scene(C);
@@ -375,13 +377,15 @@ static void rna_Sculpt_update(bContext *C, PointerRNA *UNUSED(ptr))
Object *ob = OBACT(view_layer);
if (ob) {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ob);
-
if (ob->sculpt) {
+ SCULPT_update_flat_vcol_shading(ob, scene);
+
ob->sculpt->bm_smooth_shading = ((scene->toolsettings->sculpt->flags &
SCULPT_DYNTOPO_SMOOTH_SHADING) != 0);
}
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | ND_DRAW, ob);
}
}
@@ -818,6 +822,16 @@ static void rna_def_sculpt(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Sculpt_update");
+ prop = RNA_def_property(srna, "use_flat_vcol_shading", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_DYNTOPO_FLAT_VCOL_SHADING);
+ RNA_def_property_ui_text(
+ prop,
+ "Draw Color Cells",
+ "Draw vertex colors in flat cells instead of smoothly interpolating."
+ "For debugging purposes only, does not effect rendering in eevee or cycles");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Sculpt_update");
+
prop = RNA_def_property(srna, "use_automasking_topology", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_TOPOLOGY);
RNA_def_property_ui_text(prop,
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index a94411d897e..3a4287ce35a 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -122,7 +122,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
const float spread = bmd->spread;
const bool invert_vgroup = (bmd->flags & MOD_BEVEL_INVERT_VGROUP) != 0;
- bm = BKE_mesh_to_bmesh_ex(mesh,
+ bm = BKE_mesh_to_bmesh_ex(ctx->object, mesh,
&(struct BMeshCreateParams){0},
&(struct BMeshFromMeshParams){
.calc_face_normal = true,
diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c
index 070ba3a1bcf..6242e26e251 100644
--- a/source/blender/modifiers/intern/MOD_boolean.c
+++ b/source/blender/modifiers/intern/MOD_boolean.c
@@ -1,21 +1,21 @@
/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2005 by the Blender Foundation.
- * All rights reserved.
- */
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 by the Blender Foundation.
+ * All rights reserved.
+ */
/** \file
* \ingroup modifiers
@@ -256,7 +256,8 @@ static BMesh *BMD_mesh_bm_create(
.use_toolflags = false,
}));
- BM_mesh_bm_from_me(bm,
+ BM_mesh_bm_from_me(NULL,
+ bm,
mesh_operand_ob,
&((struct BMeshFromMeshParams){
.calc_face_normal = true,
@@ -271,7 +272,8 @@ static BMesh *BMD_mesh_bm_create(
}
}
- BM_mesh_bm_from_me(bm,
+ BM_mesh_bm_from_me(NULL,
+ bm,
mesh,
&((struct BMeshFromMeshParams){
.calc_face_normal = true,
@@ -499,7 +501,8 @@ static Mesh *collection_boolean_exact(BooleanModifierData *bmd,
Mesh *me = meshes[i];
Object *ob = objects[i];
/* Need normals for triangulation. */
- BM_mesh_bm_from_me(bm,
+ BM_mesh_bm_from_me(NULL,
+ bm,
me,
&((struct BMeshFromMeshParams){
.calc_face_normal = true,
@@ -793,6 +796,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
/* Needed for multiple objects to work. */
BM_mesh_bm_to_me(NULL,
+ NULL,
bm,
mesh,
(&(struct BMeshToMeshParams){
diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c
index b28b8fd39fc..8f9da001757 100644
--- a/source/blender/modifiers/intern/MOD_decimate.c
+++ b/source/blender/modifiers/intern/MOD_decimate.c
@@ -171,7 +171,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
}
}
- bm = BKE_mesh_to_bmesh_ex(mesh,
+ bm = BKE_mesh_to_bmesh_ex(ctx->object,
+ mesh,
&(struct BMeshCreateParams){0},
&(struct BMeshFromMeshParams){
.calc_face_normal = calc_face_normal,
diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c
index e02befd7efa..5e9a51adc36 100644
--- a/source/blender/modifiers/intern/MOD_edgesplit.c
+++ b/source/blender/modifiers/intern/MOD_edgesplit.c
@@ -68,7 +68,8 @@ Mesh *doEdgeSplit(const Mesh *mesh, EdgeSplitModifierData *emd)
const bool do_split_all = do_split_angle && emd->split_angle < FLT_EPSILON;
const bool calc_face_normals = do_split_angle && !do_split_all;
- bm = BKE_mesh_to_bmesh_ex(mesh,
+ bm = BKE_mesh_to_bmesh_ex(NULL,
+ mesh,
&(struct BMeshCreateParams){0},
&(struct BMeshFromMeshParams){
.calc_face_normal = calc_face_normals,
@@ -128,7 +129,7 @@ static void initData(ModifierData *md)
MEMCPY_STRUCT_AFTER(emd, DNA_struct_default_get(EdgeSplitModifierData), modifier);
}
-static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
Mesh *result;
EdgeSplitModifierData *emd = (EdgeSplitModifierData *)md;
diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c
index 4c1179af431..eca9e4811b1 100644
--- a/source/blender/modifiers/intern/MOD_particlesystem.c
+++ b/source/blender/modifiers/intern/MOD_particlesystem.c
@@ -256,7 +256,7 @@ static void deformVertsEM(ModifierData *md,
const bool do_temp_mesh = (mesh == NULL);
if (do_temp_mesh) {
mesh = BKE_id_new_nomain(ID_ME, ((ID *)ob->data)->name);
- BM_mesh_bm_to_me(NULL, editData->bm, mesh, &((BMeshToMeshParams){0}));
+ BM_mesh_bm_to_me(NULL, NULL, editData->bm, mesh, &((BMeshToMeshParams){0}));
}
deformVerts(md, ob, mesh, vertexCos, numVerts);
diff --git a/source/blender/modifiers/intern/MOD_simulation.cc b/source/blender/modifiers/intern/MOD_simulation.cc
new file mode 100644
index 00000000000..0766c59cda6
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_simulation.cc
@@ -0,0 +1,194 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 by the Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup modifiers
+ */
+
+#include <cstring>
+#include <iostream>
+#include <string>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_float3.hh"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_defaults.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_pointcloud_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_simulation_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_lib_query.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_pointcloud.h"
+#include "BKE_screen.h"
+#include "BKE_simulation.h"
+
+#include "BLO_read_write.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "RNA_access.h"
+
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MOD_modifiertypes.h"
+#include "MOD_ui_common.h"
+
+using blender::float3;
+
+static void initData(ModifierData *md)
+{
+ SimulationModifierData *smd = (SimulationModifierData *)md;
+
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(smd, modifier));
+
+ MEMCPY_STRUCT_AFTER(smd, DNA_struct_default_get(SimulationModifierData), modifier);
+}
+
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *UNUSED(ctx))
+{
+ SimulationModifierData *smd = reinterpret_cast<SimulationModifierData *>(md);
+ UNUSED_VARS(smd);
+}
+
+static void foreachIDLink(ModifierData *md,
+ Object *UNUSED(ob),
+ IDWalkFunc UNUSED(walk),
+ void *UNUSED(userData))
+{
+ SimulationModifierData *smd = reinterpret_cast<SimulationModifierData *>(md);
+ UNUSED_VARS(smd);
+}
+
+static bool isDisabled(const struct Scene *UNUSED(scene),
+ ModifierData *md,
+ bool UNUSED(useRenderParams))
+{
+ SimulationModifierData *smd = reinterpret_cast<SimulationModifierData *>(md);
+ UNUSED_VARS(smd);
+ return false;
+}
+
+static PointCloud *modifyPointCloud(ModifierData *md,
+ const ModifierEvalContext *UNUSED(ctx),
+ PointCloud *pointcloud)
+{
+ SimulationModifierData *smd = reinterpret_cast<SimulationModifierData *>(md);
+ UNUSED_VARS(smd);
+ return pointcloud;
+}
+
+static void panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
+
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+
+ uiItemL(layout, "This modifier does nothing currently", ICON_INFO);
+
+ modifier_panel_end(layout, ptr);
+}
+
+static void panelRegister(ARegionType *region_type)
+{
+ modifier_panel_register(region_type, eModifierType_Simulation, panel_draw);
+}
+
+static void blendWrite(BlendWriter *writer, const ModifierData *md)
+{
+ const SimulationModifierData *smd = reinterpret_cast<const SimulationModifierData *>(md);
+ UNUSED_VARS(smd, writer);
+}
+
+static void blendRead(BlendDataReader *reader, ModifierData *md)
+{
+ SimulationModifierData *smd = reinterpret_cast<SimulationModifierData *>(md);
+ UNUSED_VARS(smd, reader);
+}
+
+static void copyData(const ModifierData *md, ModifierData *target, const int flag)
+{
+ const SimulationModifierData *smd = reinterpret_cast<const SimulationModifierData *>(md);
+ SimulationModifierData *tsmd = reinterpret_cast<SimulationModifierData *>(target);
+ UNUSED_VARS(smd, tsmd);
+
+ BKE_modifier_copydata_generic(md, target, flag);
+}
+
+static void freeData(ModifierData *md)
+{
+ SimulationModifierData *smd = reinterpret_cast<SimulationModifierData *>(md);
+ UNUSED_VARS(smd);
+}
+
+ModifierTypeInfo modifierType_Simulation = {
+ /* name */ "Simulation",
+ /* structName */ "SimulationModifierData",
+ /* structSize */ sizeof(SimulationModifierData),
+#ifdef WITH_GEOMETRY_NODES
+ /* srna */ &RNA_SimulationModifier,
+#else
+ /* srna */ &RNA_Modifier,
+#endif
+ /* type */ eModifierTypeType_None,
+ /* flags */ (ModifierTypeFlag)0,
+ /* icon */ ICON_PHYSICS, /* TODO: Use correct icon. */
+
+ /* copyData */ copyData,
+
+ /* deformVerts */ nullptr,
+ /* deformMatrices */ nullptr,
+ /* deformVertsEM */ nullptr,
+ /* deformMatricesEM */ nullptr,
+ /* modifyMesh */ nullptr,
+ /* modifyHair */ nullptr,
+ /* modifyPointCloud */ modifyPointCloud,
+ /* modifyVolume */ nullptr,
+
+ /* initData */ initData,
+ /* requiredDataMask */ nullptr,
+ /* freeData */ freeData,
+ /* isDisabled */ isDisabled,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ nullptr,
+ /* dependsOnNormals */ nullptr,
+ /* foreachIDLink */ foreachIDLink,
+ /* foreachTexLink */ nullptr,
+ /* freeRuntimeData */ nullptr,
+ /* panelRegister */ panelRegister,
+ /* blendWrite */ blendWrite,
+ /* blendRead */ blendRead,
+};
diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c
index 04d24ac0883..6d5fe17104c 100644
--- a/source/blender/modifiers/intern/MOD_triangulate.c
+++ b/source/blender/modifiers/intern/MOD_triangulate.c
@@ -76,7 +76,8 @@ Mesh *triangulate_mesh(Mesh *mesh,
cd_mask_extra.lmask |= CD_MASK_NORMAL;
}
- bm = BKE_mesh_to_bmesh_ex(mesh,
+ bm = BKE_mesh_to_bmesh_ex(NULL,
+ mesh,
&((struct BMeshCreateParams){0}),
&((struct BMeshFromMeshParams){
.calc_face_normal = true,
@@ -124,12 +125,11 @@ static void initData(ModifierData *md)
md->mode |= eModifierMode_Editmode;
}
-static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
TriangulateModifierData *tmd = (TriangulateModifierData *)md;
Mesh *result;
- if (!(result = triangulate_mesh(
- mesh, tmd->quad_method, tmd->ngon_method, tmd->min_vertices, tmd->flag))) {
+ if (!(result = triangulate_mesh(mesh, tmd->quad_method, tmd->ngon_method, tmd->min_vertices, tmd->flag))) {
return mesh;
}
diff --git a/source/blender/modifiers/intern/MOD_uvwarp.c b/source/blender/modifiers/intern/MOD_uvwarp.c
index 77b79167c2f..cc845854956 100644
--- a/source/blender/modifiers/intern/MOD_uvwarp.c
+++ b/source/blender/modifiers/intern/MOD_uvwarp.c
@@ -100,6 +100,7 @@ typedef struct UVWarpData {
MDeformVert *dvert;
int defgrp_index;
+ bool restrict_island;
float (*warp_mat)[4];
bool invert_vgroup;
@@ -123,6 +124,19 @@ static void uv_warp_compute(void *__restrict userdata,
int l;
if (dvert) {
+ if (data->restrict_island) {
+ for (l = 0; l < mp->totloop; l++, ml++) {
+ const float weight = data->invert_vgroup ?
+ 1.0f - BKE_defvert_find_weight(&dvert[ml->v], defgrp_index) :
+ BKE_defvert_find_weight(&dvert[ml->v], defgrp_index);
+ if (weight == 0.0f) {
+ return;
+ }
+ }
+
+ ml = &data->mloop[mp->loopstart];
+ }
+
for (l = 0; l < mp->totloop; l++, ml++, mluv++) {
float uv[2];
const float weight = data->invert_vgroup ?
@@ -221,6 +235,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
UVWarpData data = {
.mpoly = mpoly,
+ .restrict_island = umd->flag & MOD_UVWARP_RESTRICT_ISLANDS,
.mloop = mloop,
.mloopuv = mloopuv,
.dvert = dvert,
@@ -299,6 +314,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
}
modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL);
+ uiItemR(layout, ptr, "restrict_to_islands", 0, NULL, ICON_NONE);
modifier_panel_end(layout, ptr);
}
diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c
index 3d8e74d2cf5..d70a0c80c17 100644
--- a/source/blender/modifiers/intern/MOD_wireframe.c
+++ b/source/blender/modifiers/intern/MOD_wireframe.c
@@ -78,7 +78,7 @@ static Mesh *WireframeModifier_do(WireframeModifierData *wmd, Object *ob, Mesh *
const int defgrp_index = BKE_object_defgroup_name_index(ob, wmd->defgrp_name);
- bm = BKE_mesh_to_bmesh_ex(mesh,
+ bm = BKE_mesh_to_bmesh_ex(ob, mesh,
&(struct BMeshCreateParams){0},
&(struct BMeshFromMeshParams){
.calc_face_normal = true,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
index 38215b54640..c9e8e9a8dd0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
@@ -69,8 +69,8 @@ static Mesh *mesh_boolean_calc(const Mesh *mesh_a, const Mesh *mesh_b, int boole
{
struct BMeshFromMeshParams bmesh_from_mesh_params = {0};
bmesh_from_mesh_params.calc_face_normal = true;
- BM_mesh_bm_from_me(bm, mesh_b, &bmesh_from_mesh_params);
- BM_mesh_bm_from_me(bm, mesh_a, &bmesh_from_mesh_params);
+ BM_mesh_bm_from_me(NULL, bm, mesh_b, &bmesh_from_mesh_params);
+ BM_mesh_bm_from_me(NULL, bm, mesh_a, &bmesh_from_mesh_params);
}
const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c
index 5fca6f4cec6..6375c1a1d37 100644
--- a/source/blender/python/bmesh/bmesh_py_types.c
+++ b/source/blender/python/bmesh/bmesh_py_types.c
@@ -1056,7 +1056,7 @@ static PyObject *bpy_bmesh_to_mesh(BPy_BMesh *self, PyObject *args)
params.calc_object_remap = true;
}
- BM_mesh_bm_to_me(bmain, bm, me, &params);
+ BM_mesh_bm_to_me(bmain, NULL, bm, me, &params);
/* we could have the user do this but if they forget blender can easy crash
* since the references arrays for the objects derived meshes are now invalid */
@@ -1167,7 +1167,8 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject
bm = self->bm;
- BM_mesh_bm_from_me(bm,
+ BM_mesh_bm_from_me(NULL,
+ bm,
me_eval,
(&(struct BMeshFromMeshParams){
.calc_face_normal = use_fnorm,
@@ -1228,7 +1229,8 @@ static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *
bm = self->bm;
- BM_mesh_bm_from_me(bm,
+ BM_mesh_bm_from_me(NULL,
+ bm,
me,
(&(struct BMeshFromMeshParams){
.calc_face_normal = use_fnorm,
diff --git a/source/blender/render/RE_render_ext.h b/source/blender/render/RE_render_ext.h
new file mode 100644
index 00000000000..b394cfeee75
--- /dev/null
+++ b/source/blender/render/RE_render_ext.h
@@ -0,0 +1,121 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by Blender Foundation
+ * All rights reserved.
+ */
+/** \file
+ * \ingroup render
+ */
+
+#pragma once
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/* this include is for non-render pipeline exports (still old cruft here) */
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* called by meshtools */
+struct Depsgraph;
+struct ImagePool;
+struct MTex;
+struct Tex;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* texture_procedural.c */
+bool RE_texture_evaluate(const struct MTex *mtex,
+ const float vec[3],
+ const int thread,
+ struct ImagePool *pool,
+ const bool skip_load_image,
+ const bool texnode_preview,
+ /* Return arguments. */
+ float *r_intensity,
+ float r_rgba[4]) ATTR_NONNULL(1, 2, 7, 8);
+
+void texture_rgb_blend(
+ float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype);
+float texture_value_blend(float tex, float out, float fact, float facg, int blendtype);
+
+void RE_texture_rng_init(void);
+void RE_texture_rng_exit(void);
+
+/* texture_image.c */
+void ibuf_sample(struct ImBuf *ibuf, float fx, float fy, float dx, float dy, float result[4]);
+
+/* texture_pointdensity.c */
+struct PointDensity;
+
+void RE_point_density_cache(struct Depsgraph *depsgraph, struct PointDensity *pd);
+
+void RE_point_density_minmax(struct Depsgraph *depsgraph,
+ struct PointDensity *pd,
+ float r_min[3],
+ float r_max[3]);
+
+void RE_point_density_sample(struct Depsgraph *depsgraph,
+ struct PointDensity *pd,
+ const int resolution,
+ float *values);
+
+void RE_point_density_free(struct PointDensity *pd);
+
+void RE_point_density_fix_linking(void);
+
+/* texture_procedural.c */
+
+/* Texture evaluation result.
+ * Note; tr tg tb ta has to remain in this order for array access. */
+typedef struct TexResult {
+ float tin, tr, tg, tb, ta;
+ int talpha;
+ float *nor;
+} TexResult;
+
+/* This one uses nodes. */
+int multitex_ext(struct Tex *tex,
+ float texvec[3],
+ float dxt[3],
+ float dyt[3],
+ int osatex,
+ struct TexResult *texres,
+ const short thread,
+ struct ImagePool *pool,
+ bool scene_color_manage,
+ const bool skip_load_image);
+/* Nodes disabled. */
+int multitex_ext_safe(struct Tex *tex,
+ const float texvec[3],
+ struct TexResult *texres,
+ struct ImagePool *pool,
+ bool scene_color_manage,
+ const bool skip_load_image);
+/* Only for internal node usage. */
+int multitex_nodes(struct Tex *tex,
+ const float texvec[3],
+ float dxt[3],
+ float dyt[3],
+ int osatex,
+ struct TexResult *texres,
+ const short thread,
+ short which_output,
+ struct MTex *mtex,
+ struct ImagePool *pool);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/render/RE_shader_ext.h b/source/blender/render/RE_shader_ext.h
new file mode 100644
index 00000000000..d9d5a924949
--- /dev/null
+++ b/source/blender/render/RE_shader_ext.h
@@ -0,0 +1,83 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by Blender Foundation
+ * All rights reserved.
+ */
+/** \file
+ * \ingroup render
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/* this include is for texture exports */
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* localized texture result data */
+/* note; tr tg tb ta has to remain in this order */
+typedef struct TexResult {
+ float tin, tr, tg, tb, ta;
+ int talpha;
+ float *nor;
+} TexResult;
+
+typedef struct BakeImBufuserData {
+ float *displacement_buffer;
+ char *mask_buffer;
+} BakeImBufuserData;
+
+/* node shaders... */
+struct ImagePool;
+struct MTex;
+struct Tex;
+
+/* this one uses nodes */
+int multitex_ext(struct Tex *tex,
+ float texvec[3],
+ float dxt[3],
+ float dyt[3],
+ int osatex,
+ struct TexResult *texres,
+ const short thread,
+ struct ImagePool *pool,
+ bool scene_color_manage,
+ const bool skip_load_image);
+/* nodes disabled */
+int multitex_ext_safe(struct Tex *tex,
+ const float texvec[3],
+ struct TexResult *texres,
+ struct ImagePool *pool,
+ bool scene_color_manage,
+ const bool skip_load_image);
+/* only for internal node usage */
+int multitex_nodes(struct Tex *tex,
+ const float texvec[3],
+ float dxt[3],
+ float dyt[3],
+ int osatex,
+ struct TexResult *texres,
+ const short thread,
+ short which_output,
+ struct MTex *mtex,
+ struct ImagePool *pool);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/render/intern/bake_api.c b/source/blender/render/intern/bake_api.c
new file mode 100644
index 00000000000..6f5db4986f2
--- /dev/null
+++ b/source/blender/render/intern/bake_api.c
@@ -0,0 +1,1070 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup render
+ *
+ * \brief The API itself is simple.
+ * Blender sends a populated array of BakePixels to the renderer,
+ * and gets back an array of floats with the result.
+ *
+ * \section bake_api Development Notes for External Engines
+ *
+ * The Bake API is fully implemented with Python rna functions.
+ * The operator expects/call a function:
+ *
+ * ``def bake(scene, object, pass_type, object_id, pixel_array, num_pixels, depth, result)``
+ * - scene: current scene (Python object)
+ * - object: object to render (Python object)
+ * - pass_type: pass to render (string, e.g., "COMBINED", "AO", "NORMAL", ...)
+ * - object_id: index of object to bake (to use with the pixel_array)
+ * - pixel_array: list of primitive ids and barycentric coordinates to
+ * `bake(Python object, see bake_pixel)`.
+ * - num_pixels: size of pixel_array, number of pixels to bake (int)
+ * - depth: depth of pixels to return (int, assuming always 4 now)
+ * - result: array to be populated by the engine (float array, PyLong_AsVoidPtr)
+ *
+ * \note Normals are expected to be in World Space and in the +X, +Y, +Z orientation.
+ *
+ * \subsection bake_pixel BakePixel data structure
+ *
+ * pixel_array is a Python object storing BakePixel elements:
+ *
+ * \code{.c}
+ * struct BakePixel {
+ * int primitive_id, object_id;
+ * float uv[2];
+ * float du_dx, du_dy;
+ * float dv_dx, dv_dy;
+ * };
+ * \endcode
+ *
+ * In python you have access to:
+ * - ``primitive_id``, ``object_id``, ``uv``, ``du_dx``, ``du_dy``, ``next``
+ * - ``next()`` is a function that returns the next #BakePixel in the array.
+ *
+ * \note Pixels that should not be baked have ``primitive_id == -1``
+ *
+ * For a complete implementation example look at the Cycles Bake commit.
+ */
+
+#include <limits.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_bvhutils.h"
+#include "BKE_customdata.h"
+#include "BKE_image.h"
+#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_mesh_tangent.h"
+#include "BKE_node.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "RE_bake.h"
+
+/* local include */
+#include "render_types.h"
+#include "zbuf.h"
+
+typedef struct BakeDataZSpan {
+ BakePixel *pixel_array;
+ int primitive_id;
+ BakeImage *bk_image;
+ ZSpan *zspan;
+ float du_dx, du_dy;
+ float dv_dx, dv_dy;
+} BakeDataZSpan;
+
+/**
+ * struct wrapping up tangent space data
+ */
+typedef struct TSpace {
+ float tangent[3];
+ float sign;
+} TSpace;
+
+typedef struct TriTessFace {
+ const MVert *mverts[3];
+ const TSpace *tspace[3];
+ float *loop_normal[3];
+ float normal[3]; /* for flat faces */
+ bool is_smooth;
+} TriTessFace;
+
+static void store_bake_pixel(void *handle, int x, int y, float u, float v)
+{
+ BakeDataZSpan *bd = (BakeDataZSpan *)handle;
+ BakePixel *pixel;
+
+ const int width = bd->bk_image->width;
+ const size_t offset = bd->bk_image->offset;
+ const int i = offset + y * width + x;
+
+ pixel = &bd->pixel_array[i];
+ pixel->primitive_id = bd->primitive_id;
+
+ /* At this point object_id is always 0, since this function runs for the
+ * low-poly mesh only. The object_id lookup indices are set afterwards. */
+
+ copy_v2_fl2(pixel->uv, u, v);
+
+ pixel->du_dx = bd->du_dx;
+ pixel->du_dy = bd->du_dy;
+ pixel->dv_dx = bd->dv_dx;
+ pixel->dv_dy = bd->dv_dy;
+ pixel->object_id = 0;
+}
+
+void RE_bake_mask_fill(const BakePixel pixel_array[], const size_t num_pixels, char *mask)
+{
+ size_t i;
+ if (!mask) {
+ return;
+ }
+
+ /* only extend to pixels outside the mask area */
+ for (i = 0; i < num_pixels; i++) {
+ if (pixel_array[i].primitive_id != -1) {
+ mask[i] = FILTER_MASK_USED;
+ }
+ }
+}
+
+void RE_bake_margin(ImBuf *ibuf, char *mask, const int margin)
+{
+ /* margin */
+ IMB_filter_extend(ibuf, mask, margin);
+
+ if (ibuf->planes != R_IMF_PLANES_RGBA) {
+ /* clear alpha added by filtering */
+ IMB_rectfill_alpha(ibuf, 1.0f);
+ }
+}
+
+/**
+ * This function returns the coordinate and normal of a barycentric u,v
+ * for a face defined by the primitive_id index.
+ * The returned normal is actually the direction from the same barycentric coordinate
+ * in the cage to the base mesh
+ * The returned coordinate is the point in the cage mesh
+ */
+static void calc_point_from_barycentric_cage(TriTessFace *triangles_low,
+ TriTessFace *triangles_cage,
+ const float mat_low[4][4],
+ const float mat_cage[4][4],
+ int primitive_id,
+ float u,
+ float v,
+ float r_co[3],
+ float r_dir[3])
+{
+ float data[2][3][3];
+ float coord[2][3];
+ float dir[3];
+ int i;
+
+ TriTessFace *triangle[2];
+
+ triangle[0] = &triangles_low[primitive_id];
+ triangle[1] = &triangles_cage[primitive_id];
+
+ for (i = 0; i < 2; i++) {
+ copy_v3_v3(data[i][0], triangle[i]->mverts[0]->co);
+ copy_v3_v3(data[i][1], triangle[i]->mverts[1]->co);
+ copy_v3_v3(data[i][2], triangle[i]->mverts[2]->co);
+ interp_barycentric_tri_v3(data[i], u, v, coord[i]);
+ }
+
+ /* convert from local to world space */
+ mul_m4_v3(mat_low, coord[0]);
+ mul_m4_v3(mat_cage, coord[1]);
+
+ sub_v3_v3v3(dir, coord[0], coord[1]);
+ normalize_v3(dir);
+
+ copy_v3_v3(r_co, coord[1]);
+ copy_v3_v3(r_dir, dir);
+}
+
+/**
+ * This function returns the coordinate and normal of a barycentric u,v
+ * for a face defined by the primitive_id index.
+ * The returned coordinate is extruded along the normal by cage_extrusion
+ */
+static void calc_point_from_barycentric_extrusion(TriTessFace *triangles,
+ const float mat[4][4],
+ const float imat[4][4],
+ int primitive_id,
+ float u,
+ float v,
+ float cage_extrusion,
+ float r_co[3],
+ float r_dir[3],
+ const bool is_cage)
+{
+ float data[3][3];
+ float coord[3];
+ float dir[3];
+ float cage[3];
+ bool is_smooth;
+
+ TriTessFace *triangle = &triangles[primitive_id];
+ is_smooth = triangle->is_smooth || is_cage;
+
+ copy_v3_v3(data[0], triangle->mverts[0]->co);
+ copy_v3_v3(data[1], triangle->mverts[1]->co);
+ copy_v3_v3(data[2], triangle->mverts[2]->co);
+
+ interp_barycentric_tri_v3(data, u, v, coord);
+
+ if (is_smooth) {
+ normal_short_to_float_v3(data[0], triangle->mverts[0]->no);
+ normal_short_to_float_v3(data[1], triangle->mverts[1]->no);
+ normal_short_to_float_v3(data[2], triangle->mverts[2]->no);
+
+ interp_barycentric_tri_v3(data, u, v, dir);
+ normalize_v3(dir);
+ }
+ else {
+ copy_v3_v3(dir, triangle->normal);
+ }
+
+ mul_v3_v3fl(cage, dir, cage_extrusion);
+ add_v3_v3(coord, cage);
+
+ normalize_v3(dir);
+ negate_v3(dir);
+
+ /* convert from local to world space */
+ mul_m4_v3(mat, coord);
+ mul_transposed_mat3_m4_v3(imat, dir);
+ normalize_v3(dir);
+
+ copy_v3_v3(r_co, coord);
+ copy_v3_v3(r_dir, dir);
+}
+
+static void barycentric_differentials_from_position(const float co[3],
+ const float v1[3],
+ const float v2[3],
+ const float v3[3],
+ const float dxco[3],
+ const float dyco[3],
+ const float facenor[3],
+ const bool differentials,
+ float *u,
+ float *v,
+ float *dx_u,
+ float *dx_v,
+ float *dy_u,
+ float *dy_v)
+{
+ /* find most stable axis to project */
+ int axis1, axis2;
+ axis_dominant_v3(&axis1, &axis2, facenor);
+
+ /* compute u,v and derivatives */
+ float t00 = v3[axis1] - v1[axis1];
+ float t01 = v3[axis2] - v1[axis2];
+ float t10 = v3[axis1] - v2[axis1];
+ float t11 = v3[axis2] - v2[axis2];
+
+ float detsh = (t00 * t11 - t10 * t01);
+ detsh = (detsh != 0.0f) ? 1.0f / detsh : 0.0f;
+ t00 *= detsh;
+ t01 *= detsh;
+ t10 *= detsh;
+ t11 *= detsh;
+
+ *u = (v3[axis1] - co[axis1]) * t11 - (v3[axis2] - co[axis2]) * t10;
+ *v = (v3[axis2] - co[axis2]) * t00 - (v3[axis1] - co[axis1]) * t01;
+ if (differentials) {
+ *dx_u = dxco[axis1] * t11 - dxco[axis2] * t10;
+ *dx_v = dxco[axis2] * t00 - dxco[axis1] * t01;
+ *dy_u = dyco[axis1] * t11 - dyco[axis2] * t10;
+ *dy_v = dyco[axis2] * t00 - dyco[axis1] * t01;
+ }
+}
+
+/**
+ * This function populates pixel_array and returns TRUE if things are correct
+ */
+static bool cast_ray_highpoly(BVHTreeFromMesh *treeData,
+ TriTessFace *triangle_low,
+ TriTessFace *triangles[],
+ BakePixel *pixel_array_low,
+ BakePixel *pixel_array,
+ const float mat_low[4][4],
+ BakeHighPolyData *highpoly,
+ const float co[3],
+ const float dir[3],
+ const int pixel_id,
+ const int tot_highpoly,
+ const float max_ray_distance)
+{
+ int i;
+ int hit_mesh = -1;
+ float hit_distance = max_ray_distance;
+ if (hit_distance == 0.0f) {
+ /* No ray distance set, use maximum. */
+ hit_distance = FLT_MAX;
+ }
+
+ BVHTreeRayHit *hits;
+ hits = MEM_mallocN(sizeof(BVHTreeRayHit) * tot_highpoly, "Bake Highpoly to Lowpoly: BVH Rays");
+
+ for (i = 0; i < tot_highpoly; i++) {
+ float co_high[3], dir_high[3];
+
+ hits[i].index = -1;
+ /* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */
+ hits[i].dist = BVH_RAYCAST_DIST_MAX;
+
+ /* transform the ray from the world space to the highpoly space */
+ mul_v3_m4v3(co_high, highpoly[i].imat, co);
+
+ /* rotates */
+ mul_v3_mat3_m4v3(dir_high, highpoly[i].imat, dir);
+ normalize_v3(dir_high);
+
+ /* cast ray */
+ if (treeData[i].tree) {
+ BLI_bvhtree_ray_cast(treeData[i].tree,
+ co_high,
+ dir_high,
+ 0.0f,
+ &hits[i],
+ treeData[i].raycast_callback,
+ &treeData[i]);
+ }
+
+ if (hits[i].index != -1) {
+ float distance;
+ float hit_world[3];
+
+ /* distance comparison in world space */
+ mul_v3_m4v3(hit_world, highpoly[i].obmat, hits[i].co);
+ distance = len_squared_v3v3(hit_world, co);
+
+ if (distance < hit_distance) {
+ hit_mesh = i;
+ hit_distance = distance;
+ }
+ }
+ }
+
+ if (hit_mesh != -1) {
+ int primitive_id_high = hits[hit_mesh].index;
+ TriTessFace *triangle_high = &triangles[hit_mesh][primitive_id_high];
+ BakePixel *pixel_low = &pixel_array_low[pixel_id];
+ BakePixel *pixel_high = &pixel_array[pixel_id];
+
+ pixel_high->primitive_id = primitive_id_high;
+ pixel_high->object_id = hit_mesh;
+
+ /* ray direction in high poly object space */
+ float dir_high[3];
+ mul_v3_mat3_m4v3(dir_high, highpoly[hit_mesh].imat, dir);
+ normalize_v3(dir_high);
+
+ /* compute position differentials on low poly object */
+ float duco_low[3], dvco_low[3], dxco[3], dyco[3];
+ sub_v3_v3v3(duco_low, triangle_low->mverts[0]->co, triangle_low->mverts[2]->co);
+ sub_v3_v3v3(dvco_low, triangle_low->mverts[1]->co, triangle_low->mverts[2]->co);
+
+ mul_v3_v3fl(dxco, duco_low, pixel_low->du_dx);
+ madd_v3_v3fl(dxco, dvco_low, pixel_low->dv_dx);
+ mul_v3_v3fl(dyco, duco_low, pixel_low->du_dy);
+ madd_v3_v3fl(dyco, dvco_low, pixel_low->dv_dy);
+
+ /* transform from low poly to high poly object space */
+ mul_mat3_m4_v3(mat_low, dxco);
+ mul_mat3_m4_v3(mat_low, dyco);
+ mul_mat3_m4_v3(highpoly[hit_mesh].imat, dxco);
+ mul_mat3_m4_v3(highpoly[hit_mesh].imat, dyco);
+
+ /* transfer position differentials */
+ float tmp[3];
+ mul_v3_v3fl(tmp, dir_high, 1.0f / dot_v3v3(dir_high, triangle_high->normal));
+ madd_v3_v3fl(dxco, tmp, -dot_v3v3(dxco, triangle_high->normal));
+ madd_v3_v3fl(dyco, tmp, -dot_v3v3(dyco, triangle_high->normal));
+
+ /* compute barycentric differentials from position differentials */
+ barycentric_differentials_from_position(hits[hit_mesh].co,
+ triangle_high->mverts[0]->co,
+ triangle_high->mverts[1]->co,
+ triangle_high->mverts[2]->co,
+ dxco,
+ dyco,
+ triangle_high->normal,
+ true,
+ &pixel_high->uv[0],
+ &pixel_high->uv[1],
+ &pixel_high->du_dx,
+ &pixel_high->dv_dx,
+ &pixel_high->du_dy,
+ &pixel_high->dv_dy);
+
+ /* verify we have valid uvs */
+ BLI_assert(pixel_high->uv[0] >= -1e-3f && pixel_high->uv[1] >= -1e-3f &&
+ pixel_high->uv[0] + pixel_high->uv[1] <= 1.0f + 1e-3f);
+ }
+ else {
+ pixel_array[pixel_id].primitive_id = -1;
+ pixel_array[pixel_id].object_id = -1;
+ }
+
+ MEM_freeN(hits);
+ return hit_mesh != -1;
+}
+
+/**
+ * This function populates an array of verts for the triangles of a mesh
+ * Tangent and Normals are also stored
+ */
+static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval)
+{
+ int i;
+ MVert *mvert;
+ TSpace *tspace = NULL;
+ float(*loop_normals)[3] = NULL;
+
+ const int tottri = poly_to_tri_count(me->totpoly, me->totloop);
+ MLoopTri *looptri;
+ TriTessFace *triangles;
+
+ /* calculate normal for each polygon only once */
+ unsigned int mpoly_prev = UINT_MAX;
+ float no[3];
+
+ mvert = CustomData_get_layer(&me->vdata, CD_MVERT);
+ looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__);
+ triangles = MEM_callocN(sizeof(TriTessFace) * tottri, __func__);
+
+ BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri);
+
+ if (tangent) {
+ BKE_mesh_ensure_normals_for_display(me_eval);
+ BKE_mesh_calc_normals_split(me_eval);
+ BKE_mesh_calc_loop_tangents(me_eval, true, NULL, 0);
+
+ tspace = CustomData_get_layer(&me_eval->ldata, CD_TANGENT);
+ BLI_assert(tspace);
+
+ loop_normals = CustomData_get_layer(&me_eval->ldata, CD_NORMAL);
+ }
+
+ const float *precomputed_normals = CustomData_get_layer(&me->pdata, CD_NORMAL);
+ const bool calculate_normal = precomputed_normals ? false : true;
+
+ for (i = 0; i < tottri; i++) {
+ const MLoopTri *lt = &looptri[i];
+ const MPoly *mp = &me->mpoly[lt->poly];
+
+ triangles[i].mverts[0] = &mvert[me->mloop[lt->tri[0]].v];
+ triangles[i].mverts[1] = &mvert[me->mloop[lt->tri[1]].v];
+ triangles[i].mverts[2] = &mvert[me->mloop[lt->tri[2]].v];
+ triangles[i].is_smooth = (mp->flag & ME_SMOOTH) != 0;
+
+ if (tangent) {
+ triangles[i].tspace[0] = &tspace[lt->tri[0]];
+ triangles[i].tspace[1] = &tspace[lt->tri[1]];
+ triangles[i].tspace[2] = &tspace[lt->tri[2]];
+ }
+
+ if (loop_normals) {
+ triangles[i].loop_normal[0] = loop_normals[lt->tri[0]];
+ triangles[i].loop_normal[1] = loop_normals[lt->tri[1]];
+ triangles[i].loop_normal[2] = loop_normals[lt->tri[2]];
+ }
+
+ if (calculate_normal) {
+ if (lt->poly != mpoly_prev) {
+ BKE_mesh_calc_poly_normal(mp, &me->mloop[mp->loopstart], me->mvert, no);
+ mpoly_prev = lt->poly;
+ }
+ copy_v3_v3(triangles[i].normal, no);
+ }
+ else {
+ copy_v3_v3(triangles[i].normal, &precomputed_normals[lt->poly]);
+ }
+ }
+
+ MEM_freeN(looptri);
+
+ return triangles;
+}
+
+bool RE_bake_pixels_populate_from_objects(struct Mesh *me_low,
+ BakePixel pixel_array_from[],
+ BakePixel pixel_array_to[],
+ BakeHighPolyData highpoly[],
+ const int tot_highpoly,
+ const size_t num_pixels,
+ const bool is_custom_cage,
+ const float cage_extrusion,
+ const float max_ray_distance,
+ float mat_low[4][4],
+ float mat_cage[4][4],
+ struct Mesh *me_cage)
+{
+ size_t i;
+ int primitive_id;
+ float u, v;
+ float imat_low[4][4];
+ bool is_cage = me_cage != NULL;
+ bool result = true;
+
+ Mesh *me_eval_low = NULL;
+ Mesh **me_highpoly;
+ BVHTreeFromMesh *treeData;
+
+ /* Note: all coordinates are in local space */
+ TriTessFace *tris_low = NULL;
+ TriTessFace *tris_cage = NULL;
+ TriTessFace **tris_high;
+
+ /* assume all lowpoly tessfaces can be quads */
+ tris_high = MEM_callocN(sizeof(TriTessFace *) * tot_highpoly, "MVerts Highpoly Mesh Array");
+
+ /* assume all highpoly tessfaces are triangles */
+ me_highpoly = MEM_mallocN(sizeof(Mesh *) * tot_highpoly, "Highpoly Derived Meshes");
+ treeData = MEM_callocN(sizeof(BVHTreeFromMesh) * tot_highpoly, "Highpoly BVH Trees");
+
+ if (!is_cage) {
+ me_eval_low = BKE_mesh_copy_for_eval(me_low, false);
+ tris_low = mesh_calc_tri_tessface(me_low, true, me_eval_low);
+ }
+ else if (is_custom_cage) {
+ tris_low = mesh_calc_tri_tessface(me_low, false, NULL);
+ tris_cage = mesh_calc_tri_tessface(me_cage, false, NULL);
+ }
+ else {
+ tris_cage = mesh_calc_tri_tessface(me_cage, false, NULL);
+ }
+
+ invert_m4_m4(imat_low, mat_low);
+
+ for (i = 0; i < tot_highpoly; i++) {
+ tris_high[i] = mesh_calc_tri_tessface(highpoly[i].me, false, NULL);
+
+ me_highpoly[i] = highpoly[i].me;
+ BKE_mesh_runtime_looptri_ensure(me_highpoly[i]);
+
+ if (me_highpoly[i]->runtime.looptris.len != 0) {
+ /* Create a bvh-tree for each highpoly object */
+ BKE_bvhtree_from_mesh_get(&treeData[i], me_highpoly[i], BVHTREE_FROM_LOOPTRI, 2);
+
+ if (treeData[i].tree == NULL) {
+ printf("Baking: out of memory while creating BHVTree for object \"%s\"\n",
+ highpoly[i].ob->id.name + 2);
+ result = false;
+ goto cleanup;
+ }
+ }
+ }
+
+ for (i = 0; i < num_pixels; i++) {
+ float co[3];
+ float dir[3];
+ TriTessFace *tri_low;
+
+ primitive_id = pixel_array_from[i].primitive_id;
+
+ if (primitive_id == -1) {
+ pixel_array_to[i].primitive_id = -1;
+ continue;
+ }
+
+ u = pixel_array_from[i].uv[0];
+ v = pixel_array_from[i].uv[1];
+
+ /* calculate from low poly mesh cage */
+ if (is_custom_cage) {
+ calc_point_from_barycentric_cage(
+ tris_low, tris_cage, mat_low, mat_cage, primitive_id, u, v, co, dir);
+ tri_low = &tris_cage[primitive_id];
+ }
+ else if (is_cage) {
+ calc_point_from_barycentric_extrusion(
+ tris_cage, mat_low, imat_low, primitive_id, u, v, cage_extrusion, co, dir, true);
+ tri_low = &tris_cage[primitive_id];
+ }
+ else {
+ calc_point_from_barycentric_extrusion(
+ tris_low, mat_low, imat_low, primitive_id, u, v, cage_extrusion, co, dir, false);
+ tri_low = &tris_low[primitive_id];
+ }
+
+ /* cast ray */
+ if (!cast_ray_highpoly(treeData,
+ tri_low,
+ tris_high,
+ pixel_array_from,
+ pixel_array_to,
+ mat_low,
+ highpoly,
+ co,
+ dir,
+ i,
+ tot_highpoly,
+ max_ray_distance)) {
+ /* if it fails mask out the original pixel array */
+ pixel_array_from[i].primitive_id = -1;
+ }
+ }
+
+ /* garbage collection */
+cleanup:
+ for (i = 0; i < tot_highpoly; i++) {
+ free_bvhtree_from_mesh(&treeData[i]);
+
+ if (tris_high[i]) {
+ MEM_freeN(tris_high[i]);
+ }
+ }
+
+ MEM_freeN(tris_high);
+ MEM_freeN(treeData);
+ MEM_freeN(me_highpoly);
+
+ if (me_eval_low) {
+ BKE_id_free(NULL, me_eval_low);
+ }
+ if (tris_low) {
+ MEM_freeN(tris_low);
+ }
+ if (tris_cage) {
+ MEM_freeN(tris_cage);
+ }
+
+ return result;
+}
+
+static void bake_differentials(BakeDataZSpan *bd,
+ const float *uv1,
+ const float *uv2,
+ const float *uv3)
+{
+ float A;
+
+ /* assumes dPdu = P1 - P3 and dPdv = P2 - P3 */
+ A = (uv2[0] - uv1[0]) * (uv3[1] - uv1[1]) - (uv3[0] - uv1[0]) * (uv2[1] - uv1[1]);
+
+ if (fabsf(A) > FLT_EPSILON) {
+ A = 0.5f / A;
+
+ bd->du_dx = (uv2[1] - uv3[1]) * A;
+ bd->dv_dx = (uv3[1] - uv1[1]) * A;
+
+ bd->du_dy = (uv3[0] - uv2[0]) * A;
+ bd->dv_dy = (uv1[0] - uv3[0]) * A;
+ }
+ else {
+ bd->du_dx = bd->du_dy = 0.0f;
+ bd->dv_dx = bd->dv_dy = 0.0f;
+ }
+}
+
+void RE_bake_pixels_populate(Mesh *me,
+ BakePixel pixel_array[],
+ const size_t num_pixels,
+ const BakeImages *bake_images,
+ const char *uv_layer)
+{
+ const MLoopUV *mloopuv;
+ if ((uv_layer == NULL) || (uv_layer[0] == '\0')) {
+ mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV);
+ }
+ else {
+ int uv_id = CustomData_get_named_layer(&me->ldata, CD_MLOOPUV, uv_layer);
+ mloopuv = CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, uv_id);
+ }
+
+ if (mloopuv == NULL) {
+ return;
+ }
+
+ BakeDataZSpan bd;
+ bd.pixel_array = pixel_array;
+ bd.zspan = MEM_callocN(sizeof(ZSpan) * bake_images->size, "bake zspan");
+
+ /* initialize all pixel arrays so we know which ones are 'blank' */
+ for (int i = 0; i < num_pixels; i++) {
+ pixel_array[i].primitive_id = -1;
+ pixel_array[i].object_id = 0;
+ }
+
+ for (int i = 0; i < bake_images->size; i++) {
+ zbuf_alloc_span(&bd.zspan[i], bake_images->data[i].width, bake_images->data[i].height);
+ }
+
+ const int tottri = poly_to_tri_count(me->totpoly, me->totloop);
+ MLoopTri *looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__);
+
+ BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri);
+
+ for (int i = 0; i < tottri; i++) {
+ const MLoopTri *lt = &looptri[i];
+ const MPoly *mp = &me->mpoly[lt->poly];
+ float vec[3][2];
+ int mat_nr = mp->mat_nr;
+ int image_id = bake_images->lookup[mat_nr];
+
+ if (image_id < 0) {
+ continue;
+ }
+
+ bd.bk_image = &bake_images->data[image_id];
+ bd.primitive_id = i;
+
+ for (int a = 0; a < 3; a++) {
+ const float *uv = mloopuv[lt->tri[a]].uv;
+
+ /* Note, workaround for pixel aligned UVs which are common and can screw up our
+ * intersection tests where a pixel gets in between 2 faces or the middle of a quad,
+ * camera aligned quads also have this problem but they are less common.
+ * Add a small offset to the UVs, fixes bug T18685 - Campbell */
+ vec[a][0] = uv[0] * (float)bd.bk_image->width - (0.5f + 0.001f);
+ vec[a][1] = uv[1] * (float)bd.bk_image->height - (0.5f + 0.002f);
+ }
+
+ bake_differentials(&bd, vec[0], vec[1], vec[2]);
+ zspan_scanconvert(&bd.zspan[image_id], (void *)&bd, vec[0], vec[1], vec[2], store_bake_pixel);
+ }
+
+ for (int i = 0; i < bake_images->size; i++) {
+ zbuf_free_span(&bd.zspan[i]);
+ }
+
+ MEM_freeN(looptri);
+ MEM_freeN(bd.zspan);
+}
+
+/* ******************** NORMALS ************************ */
+
+/**
+ * convert a normalized normal to the -1.0 1.0 range
+ * the input is expected to be POS_X, POS_Y, POS_Z
+ */
+static void normal_uncompress(float out[3], const float in[3])
+{
+ int i;
+ for (i = 0; i < 3; i++) {
+ out[i] = 2.0f * in[i] - 1.0f;
+ }
+}
+
+static void normal_compress(float out[3],
+ const float in[3],
+ const eBakeNormalSwizzle normal_swizzle[3])
+{
+ const int swizzle_index[6] = {
+ 0, /* R_BAKE_POSX */
+ 1, /* R_BAKE_POSY */
+ 2, /* R_BAKE_POSZ */
+ 0, /* R_BAKE_NEGX */
+ 1, /* R_BAKE_NEGY */
+ 2, /* R_BAKE_NEGZ */
+ };
+ const float swizzle_sign[6] = {
+ +1.0f, /* R_BAKE_POSX */
+ +1.0f, /* R_BAKE_POSY */
+ +1.0f, /* R_BAKE_POSZ */
+ -1.0f, /* R_BAKE_NEGX */
+ -1.0f, /* R_BAKE_NEGY */
+ -1.0f, /* R_BAKE_NEGZ */
+ };
+
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ int index;
+ float sign;
+
+ sign = swizzle_sign[normal_swizzle[i]];
+ index = swizzle_index[normal_swizzle[i]];
+
+ /*
+ * There is a small 1e-5f bias for precision issues. otherwise
+ * we randomly get 127 or 128 for neutral colors in tangent maps.
+ * we choose 128 because it is the convention flat color. *
+ */
+
+ out[i] = sign * in[index] / 2.0f + 0.5f + 1e-5f;
+ }
+}
+
+/**
+ * This function converts an object space normal map
+ * to a tangent space normal map for a given low poly mesh.
+ */
+void RE_bake_normal_world_to_tangent(const BakePixel pixel_array[],
+ const size_t num_pixels,
+ const int depth,
+ float result[],
+ Mesh *me,
+ const eBakeNormalSwizzle normal_swizzle[3],
+ float mat[4][4])
+{
+ size_t i;
+
+ TriTessFace *triangles;
+
+ Mesh *me_eval = BKE_mesh_copy_for_eval(me, false);
+
+ triangles = mesh_calc_tri_tessface(me, true, me_eval);
+
+ BLI_assert(num_pixels >= 3);
+
+ for (i = 0; i < num_pixels; i++) {
+ TriTessFace *triangle;
+ float tangents[3][3];
+ float normals[3][3];
+ float signs[3];
+ int j;
+
+ float tangent[3];
+ float normal[3];
+ float binormal[3];
+ float sign;
+ float u, v, w;
+
+ float tsm[3][3]; /* tangent space matrix */
+ float itsm[3][3];
+
+ size_t offset;
+ float nor[3]; /* texture normal */
+
+ bool is_smooth;
+
+ int primitive_id = pixel_array[i].primitive_id;
+
+ offset = i * depth;
+
+ if (primitive_id == -1) {
+ if (depth == 4) {
+ copy_v4_fl4(&result[offset], 0.5f, 0.5f, 1.0f, 1.0f);
+ }
+ else {
+ copy_v3_fl3(&result[offset], 0.5f, 0.5f, 1.0f);
+ }
+ continue;
+ }
+
+ triangle = &triangles[primitive_id];
+ is_smooth = triangle->is_smooth;
+
+ for (j = 0; j < 3; j++) {
+ const TSpace *ts;
+
+ if (is_smooth) {
+ if (triangle->loop_normal[j]) {
+ copy_v3_v3(normals[j], triangle->loop_normal[j]);
+ }
+ else {
+ normal_short_to_float_v3(normals[j], triangle->mverts[j]->no);
+ }
+ }
+
+ ts = triangle->tspace[j];
+ copy_v3_v3(tangents[j], ts->tangent);
+ signs[j] = ts->sign;
+ }
+
+ u = pixel_array[i].uv[0];
+ v = pixel_array[i].uv[1];
+ w = 1.0f - u - v;
+
+ /* normal */
+ if (is_smooth) {
+ interp_barycentric_tri_v3(normals, u, v, normal);
+ }
+ else {
+ copy_v3_v3(normal, triangle->normal);
+ }
+
+ /* tangent */
+ interp_barycentric_tri_v3(tangents, u, v, tangent);
+
+ /* sign */
+ /* The sign is the same at all face vertices for any non degenerate face.
+ * Just in case we clamp the interpolated value though. */
+ sign = (signs[0] * u + signs[1] * v + signs[2] * w) < 0 ? (-1.0f) : 1.0f;
+
+ /* binormal */
+ /* B = sign * cross(N, T) */
+ cross_v3_v3v3(binormal, normal, tangent);
+ mul_v3_fl(binormal, sign);
+
+ /* populate tangent space matrix */
+ copy_v3_v3(tsm[0], tangent);
+ copy_v3_v3(tsm[1], binormal);
+ copy_v3_v3(tsm[2], normal);
+
+ /* texture values */
+ normal_uncompress(nor, &result[offset]);
+
+ /* converts from world space to local space */
+ mul_transposed_mat3_m4_v3(mat, nor);
+
+ invert_m3_m3(itsm, tsm);
+ mul_m3_v3(itsm, nor);
+ normalize_v3(nor);
+
+ /* save back the values */
+ normal_compress(&result[offset], nor, normal_swizzle);
+ }
+
+ /* garbage collection */
+ MEM_freeN(triangles);
+
+ if (me_eval) {
+ BKE_id_free(NULL, me_eval);
+ }
+}
+
+void RE_bake_normal_world_to_object(const BakePixel pixel_array[],
+ const size_t num_pixels,
+ const int depth,
+ float result[],
+ struct Object *ob,
+ const eBakeNormalSwizzle normal_swizzle[3])
+{
+ size_t i;
+ float iobmat[4][4];
+
+ invert_m4_m4(iobmat, ob->obmat);
+
+ for (i = 0; i < num_pixels; i++) {
+ size_t offset;
+ float nor[3];
+
+ if (pixel_array[i].primitive_id == -1) {
+ continue;
+ }
+
+ offset = i * depth;
+ normal_uncompress(nor, &result[offset]);
+
+ /* rotates only without translation */
+ mul_mat3_m4_v3(iobmat, nor);
+ normalize_v3(nor);
+
+ /* save back the values */
+ normal_compress(&result[offset], nor, normal_swizzle);
+ }
+}
+
+void RE_bake_normal_world_to_world(const BakePixel pixel_array[],
+ const size_t num_pixels,
+ const int depth,
+ float result[],
+ const eBakeNormalSwizzle normal_swizzle[3])
+{
+ size_t i;
+
+ for (i = 0; i < num_pixels; i++) {
+ size_t offset;
+ float nor[3];
+
+ if (pixel_array[i].primitive_id == -1) {
+ continue;
+ }
+
+ offset = i * depth;
+ normal_uncompress(nor, &result[offset]);
+
+ /* save back the values */
+ normal_compress(&result[offset], nor, normal_swizzle);
+ }
+}
+
+void RE_bake_ibuf_clear(Image *image, const bool is_tangent)
+{
+ ImBuf *ibuf;
+ void *lock;
+
+ const float vec_alpha[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ const float vec_solid[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ const float nor_alpha[4] = {0.5f, 0.5f, 1.0f, 0.0f};
+ const float nor_solid[4] = {0.5f, 0.5f, 1.0f, 1.0f};
+
+ ibuf = BKE_image_acquire_ibuf(image, NULL, &lock);
+ BLI_assert(ibuf);
+
+ if (is_tangent) {
+ IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? nor_alpha : nor_solid);
+ }
+ else {
+ IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? vec_alpha : vec_solid);
+ }
+
+ BKE_image_release_ibuf(image, ibuf, lock);
+}
+
+/* ************************************************************* */
+
+int RE_pass_depth(const eScenePassType pass_type)
+{
+ /* IMB_buffer_byte_from_float assumes 4 channels
+ * making it work for now - XXX */
+ return 4;
+
+ switch (pass_type) {
+ case SCE_PASS_Z:
+ case SCE_PASS_AO:
+ case SCE_PASS_MIST: {
+ return 1;
+ }
+ case SCE_PASS_UV: {
+ return 2;
+ }
+ case SCE_PASS_COMBINED:
+ case SCE_PASS_SHADOW:
+ case SCE_PASS_NORMAL:
+ case SCE_PASS_VECTOR:
+ case SCE_PASS_INDEXOB: /* XXX double check */
+ case SCE_PASS_RAYHITS: /* XXX double check */
+ case SCE_PASS_EMIT:
+ case SCE_PASS_ENVIRONMENT:
+ case SCE_PASS_INDEXMA:
+ case SCE_PASS_DIFFUSE_DIRECT:
+ case SCE_PASS_DIFFUSE_INDIRECT:
+ case SCE_PASS_DIFFUSE_COLOR:
+ case SCE_PASS_GLOSSY_DIRECT:
+ case SCE_PASS_GLOSSY_INDIRECT:
+ case SCE_PASS_GLOSSY_COLOR:
+ case SCE_PASS_TRANSM_DIRECT:
+ case SCE_PASS_TRANSM_INDIRECT:
+ case SCE_PASS_TRANSM_COLOR:
+ case SCE_PASS_SUBSURFACE_DIRECT:
+ case SCE_PASS_SUBSURFACE_INDIRECT:
+ case SCE_PASS_SUBSURFACE_COLOR:
+ default: {
+ return 3;
+ }
+ }
+}
diff --git a/source/blender/render/intern/external_engine.c b/source/blender/render/intern/external_engine.c
new file mode 100644
index 00000000000..769077c0e8c
--- /dev/null
+++ b/source/blender/render/intern/external_engine.c
@@ -0,0 +1,1032 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup render
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLT_translation.h"
+
+#include "BLI_ghash.h"
+#include "BLI_listbase.h"
+#include "BLI_math_bits.h"
+#include "BLI_rect.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_object_types.h"
+
+#include "BKE_camera.h"
+#include "BKE_colortools.h"
+#include "BKE_global.h"
+#include "BKE_layer.h"
+#include "BKE_node.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_debug.h"
+#include "DEG_depsgraph_query.h"
+
+#include "RNA_access.h"
+
+#ifdef WITH_PYTHON
+# include "BPY_extern.h"
+#endif
+
+#include "RE_bake.h"
+#include "RE_engine.h"
+#include "RE_pipeline.h"
+
+#include "DRW_engine.h"
+
+#include "initrender.h"
+#include "pipeline.h"
+#include "render_result.h"
+#include "render_types.h"
+
+/* Render Engine Types */
+
+ListBase R_engines = {NULL, NULL};
+
+void RE_engines_init(void)
+{
+ DRW_engines_register();
+}
+
+void RE_engines_exit(void)
+{
+ RenderEngineType *type, *next;
+
+ DRW_engines_free();
+
+ for (type = R_engines.first; type; type = next) {
+ next = type->next;
+
+ BLI_remlink(&R_engines, type);
+
+ if (!(type->flag & RE_INTERNAL)) {
+ if (type->rna_ext.free) {
+ type->rna_ext.free(type->rna_ext.data);
+ }
+
+ MEM_freeN(type);
+ }
+ }
+}
+
+void RE_engines_register(RenderEngineType *render_type)
+{
+ if (render_type->draw_engine) {
+ DRW_engine_register(render_type->draw_engine);
+ }
+ BLI_addtail(&R_engines, render_type);
+}
+
+RenderEngineType *RE_engines_find(const char *idname)
+{
+ RenderEngineType *type;
+
+ type = BLI_findstring(&R_engines, idname, offsetof(RenderEngineType, idname));
+ if (!type) {
+ type = BLI_findstring(&R_engines, "BLENDER_EEVEE", offsetof(RenderEngineType, idname));
+ }
+
+ return type;
+}
+
+bool RE_engine_is_external(const Render *re)
+{
+ return (re->engine && re->engine->type && re->engine->type->render);
+}
+
+bool RE_engine_is_opengl(RenderEngineType *render_type)
+{
+ /* TODO refine? Can we have ogl render engine without ogl render pipeline? */
+ return (render_type->draw_engine != NULL) && DRW_engine_render_support(render_type->draw_engine);
+}
+
+/* Create, Free */
+
+RenderEngine *RE_engine_create(RenderEngineType *type)
+{
+ RenderEngine *engine = MEM_callocN(sizeof(RenderEngine), "RenderEngine");
+ engine->type = type;
+
+ BLI_mutex_init(&engine->update_render_passes_mutex);
+
+ return engine;
+}
+
+void RE_engine_free(RenderEngine *engine)
+{
+#ifdef WITH_PYTHON
+ if (engine->py_instance) {
+ BPY_DECREF_RNA_INVALIDATE(engine->py_instance);
+ }
+#endif
+
+ BLI_mutex_end(&engine->update_render_passes_mutex);
+
+ MEM_freeN(engine);
+}
+
+/* Bake Render Results */
+
+static RenderResult *render_result_from_bake(RenderEngine *engine, int x, int y, int w, int h)
+{
+ /* Create render result with specified size. */
+ RenderResult *rr = MEM_callocN(sizeof(RenderResult), __func__);
+
+ rr->rectx = w;
+ rr->recty = h;
+ rr->tilerect.xmin = x;
+ rr->tilerect.ymin = y;
+ rr->tilerect.xmax = x + w;
+ rr->tilerect.ymax = y + h;
+
+ /* Add single baking render layer. */
+ RenderLayer *rl = MEM_callocN(sizeof(RenderLayer), "bake render layer");
+ rl->rectx = w;
+ rl->recty = h;
+ BLI_addtail(&rr->layers, rl);
+
+ /* Add render passes. */
+ RenderPass *result_pass = render_layer_add_pass(
+ rr, rl, engine->bake.depth, RE_PASSNAME_COMBINED, "", "RGBA");
+ RenderPass *primitive_pass = render_layer_add_pass(rr, rl, 4, "BakePrimitive", "", "RGBA");
+ RenderPass *differential_pass = render_layer_add_pass(rr, rl, 4, "BakeDifferential", "", "RGBA");
+
+ /* Fill render passes from bake pixel array, to be read by the render engine. */
+ for (int ty = 0; ty < h; ty++) {
+ size_t offset = ty * w * 4;
+ float *primitive = primitive_pass->rect + offset;
+ float *differential = differential_pass->rect + offset;
+
+ size_t bake_offset = (y + ty) * engine->bake.width + x;
+ const BakePixel *bake_pixel = engine->bake.pixels + bake_offset;
+
+ for (int tx = 0; tx < w; tx++) {
+ if (bake_pixel->object_id != engine->bake.object_id) {
+ primitive[0] = int_as_float(-1);
+ primitive[1] = int_as_float(-1);
+ }
+ else {
+ primitive[0] = int_as_float(bake_pixel->object_id);
+ primitive[1] = int_as_float(bake_pixel->primitive_id);
+ primitive[2] = bake_pixel->uv[0];
+ primitive[3] = bake_pixel->uv[1];
+
+ differential[0] = bake_pixel->du_dx;
+ differential[1] = bake_pixel->du_dy;
+ differential[2] = bake_pixel->dv_dx;
+ differential[3] = bake_pixel->dv_dy;
+ }
+
+ primitive += 4;
+ differential += 4;
+ bake_pixel++;
+ }
+ }
+
+ /* Initialize tile render result from full image bake result. */
+ for (int ty = 0; ty < h; ty++) {
+ size_t offset = ty * w * engine->bake.depth;
+ size_t bake_offset = ((y + ty) * engine->bake.width + x) * engine->bake.depth;
+ size_t size = w * engine->bake.depth * sizeof(float);
+
+ memcpy(result_pass->rect + offset, engine->bake.result + bake_offset, size);
+ }
+
+ return rr;
+}
+
+static void render_result_to_bake(RenderEngine *engine, RenderResult *rr)
+{
+ RenderPass *rpass = RE_pass_find_by_name(rr->layers.first, RE_PASSNAME_COMBINED, "");
+
+ if (!rpass) {
+ return;
+ }
+
+ /* Copy from tile render result to full image bake result. */
+ int x = rr->tilerect.xmin;
+ int y = rr->tilerect.ymin;
+ int w = rr->tilerect.xmax - rr->tilerect.xmin;
+ int h = rr->tilerect.ymax - rr->tilerect.ymin;
+
+ for (int ty = 0; ty < h; ty++) {
+ size_t offset = ty * w * engine->bake.depth;
+ size_t bake_offset = ((y + ty) * engine->bake.width + x) * engine->bake.depth;
+ size_t size = w * engine->bake.depth * sizeof(float);
+
+ memcpy(engine->bake.result + bake_offset, rpass->rect + offset, size);
+ }
+}
+
+/* Render Results */
+
+static RenderPart *get_part_from_result(Render *re, RenderResult *result)
+{
+ rcti key = result->tilerect;
+ BLI_rcti_translate(&key, re->disprect.xmin, re->disprect.ymin);
+
+ return BLI_ghash_lookup(re->parts, &key);
+}
+
+RenderResult *RE_engine_begin_result(
+ RenderEngine *engine, int x, int y, int w, int h, const char *layername, const char *viewname)
+{
+ if (engine->bake.pixels) {
+ RenderResult *result = render_result_from_bake(engine, x, y, w, h);
+ BLI_addtail(&engine->fullresult, result);
+ return result;
+ }
+
+ Render *re = engine->re;
+ RenderResult *result;
+ rcti disprect;
+
+ /* ensure the coordinates are within the right limits */
+ CLAMP(x, 0, re->result->rectx);
+ CLAMP(y, 0, re->result->recty);
+ CLAMP(w, 0, re->result->rectx);
+ CLAMP(h, 0, re->result->recty);
+
+ if (x + w > re->result->rectx) {
+ w = re->result->rectx - x;
+ }
+ if (y + h > re->result->recty) {
+ h = re->result->recty - y;
+ }
+
+ /* allocate a render result */
+ disprect.xmin = x;
+ disprect.xmax = x + w;
+ disprect.ymin = y;
+ disprect.ymax = y + h;
+
+ result = render_result_new(re, &disprect, 0, RR_USE_MEM, layername, viewname);
+
+ /* todo: make this thread safe */
+
+ /* can be NULL if we CLAMP the width or height to 0 */
+ if (result) {
+ render_result_clone_passes(re, result, viewname);
+
+ RenderPart *pa;
+
+ /* Copy EXR tile settings, so pipeline knows whether this is a result
+ * for Save Buffers enabled rendering.
+ */
+ result->do_exr_tile = re->result->do_exr_tile;
+
+ BLI_addtail(&engine->fullresult, result);
+
+ result->tilerect.xmin += re->disprect.xmin;
+ result->tilerect.xmax += re->disprect.xmin;
+ result->tilerect.ymin += re->disprect.ymin;
+ result->tilerect.ymax += re->disprect.ymin;
+
+ pa = get_part_from_result(re, result);
+
+ if (pa) {
+ pa->status = PART_STATUS_IN_PROGRESS;
+ }
+ }
+
+ return result;
+}
+
+void RE_engine_update_result(RenderEngine *engine, RenderResult *result)
+{
+ if (engine->bake.pixels) {
+ /* No interactive baking updates for now. */
+ return;
+ }
+
+ Render *re = engine->re;
+
+ if (result) {
+ render_result_merge(re->result, result);
+ result->renlay = result->layers.first; /* weak, draws first layer always */
+ re->display_update(re->duh, result, NULL);
+ }
+}
+
+void RE_engine_add_pass(RenderEngine *engine,
+ const char *name,
+ int channels,
+ const char *chan_id,
+ const char *layername)
+{
+ Render *re = engine->re;
+
+ if (!re || !re->result) {
+ return;
+ }
+
+ RE_create_render_pass(re->result, name, channels, chan_id, layername, NULL);
+}
+
+void RE_engine_end_result(
+ RenderEngine *engine, RenderResult *result, bool cancel, bool highlight, bool merge_results)
+{
+ Render *re = engine->re;
+
+ if (!result) {
+ return;
+ }
+
+ if (engine->bake.pixels) {
+ render_result_to_bake(engine, result);
+ BLI_remlink(&engine->fullresult, result);
+ render_result_free(result);
+ return;
+ }
+
+ /* merge. on break, don't merge in result for preview renders, looks nicer */
+ if (!highlight) {
+ /* for exr tile render, detect tiles that are done */
+ RenderPart *pa = get_part_from_result(re, result);
+
+ if (pa) {
+ pa->status = (!cancel && merge_results) ? PART_STATUS_MERGED : PART_STATUS_RENDERED;
+ }
+ else if (re->result->do_exr_tile) {
+ /* If written result does not match any tile and we are using save
+ * buffers, we are going to get OpenEXR save errors. */
+ fprintf(stderr, "RenderEngine.end_result: dimensions do not match any OpenEXR tile.\n");
+ }
+ }
+
+ if (!cancel || merge_results) {
+ if (re->result->do_exr_tile) {
+ if (!cancel && merge_results) {
+ render_result_exr_file_merge(re->result, result, re->viewname);
+ render_result_merge(re->result, result);
+ }
+ }
+ else if (!(re->test_break(re->tbh) && (re->r.scemode & R_BUTS_PREVIEW))) {
+ render_result_merge(re->result, result);
+ }
+
+ /* draw */
+ if (!re->test_break(re->tbh)) {
+ result->renlay = result->layers.first; /* weak, draws first layer always */
+ re->display_update(re->duh, result, NULL);
+ }
+ }
+
+ /* free */
+ BLI_remlink(&engine->fullresult, result);
+ render_result_free(result);
+}
+
+RenderResult *RE_engine_get_result(RenderEngine *engine)
+{
+ return engine->re->result;
+}
+
+/* Cancel */
+
+bool RE_engine_test_break(RenderEngine *engine)
+{
+ Render *re = engine->re;
+
+ if (re) {
+ return re->test_break(re->tbh);
+ }
+
+ return 0;
+}
+
+/* Statistics */
+
+void RE_engine_update_stats(RenderEngine *engine, const char *stats, const char *info)
+{
+ Render *re = engine->re;
+
+ /* stats draw callback */
+ if (re) {
+ re->i.statstr = stats;
+ re->i.infostr = info;
+ re->stats_draw(re->sdh, &re->i);
+ re->i.infostr = NULL;
+ re->i.statstr = NULL;
+ }
+
+ /* set engine text */
+ engine->text[0] = '\0';
+
+ if (stats && stats[0] && info && info[0]) {
+ BLI_snprintf(engine->text, sizeof(engine->text), "%s | %s", stats, info);
+ }
+ else if (info && info[0]) {
+ BLI_strncpy(engine->text, info, sizeof(engine->text));
+ }
+ else if (stats && stats[0]) {
+ BLI_strncpy(engine->text, stats, sizeof(engine->text));
+ }
+}
+
+void RE_engine_update_progress(RenderEngine *engine, float progress)
+{
+ Render *re = engine->re;
+
+ if (re) {
+ CLAMP(progress, 0.0f, 1.0f);
+ re->progress(re->prh, progress);
+ }
+}
+
+void RE_engine_update_memory_stats(RenderEngine *engine, float mem_used, float mem_peak)
+{
+ Render *re = engine->re;
+
+ if (re) {
+ re->i.mem_used = mem_used;
+ re->i.mem_peak = mem_peak;
+ }
+}
+
+void RE_engine_report(RenderEngine *engine, int type, const char *msg)
+{
+ Render *re = engine->re;
+
+ if (re) {
+ BKE_report(engine->re->reports, type, msg);
+ }
+ else if (engine->reports) {
+ BKE_report(engine->reports, type, msg);
+ }
+}
+
+void RE_engine_set_error_message(RenderEngine *engine, const char *msg)
+{
+ Render *re = engine->re;
+ if (re != NULL) {
+ RenderResult *rr = RE_AcquireResultRead(re);
+ if (rr) {
+ if (rr->error != NULL) {
+ MEM_freeN(rr->error);
+ }
+ rr->error = BLI_strdup(msg);
+ }
+ RE_ReleaseResult(re);
+ }
+}
+
+const char *RE_engine_active_view_get(RenderEngine *engine)
+{
+ Render *re = engine->re;
+ return RE_GetActiveRenderView(re);
+}
+
+void RE_engine_active_view_set(RenderEngine *engine, const char *viewname)
+{
+ Render *re = engine->re;
+ RE_SetActiveRenderView(re, viewname);
+}
+
+float RE_engine_get_camera_shift_x(RenderEngine *engine, Object *camera, bool use_spherical_stereo)
+{
+ /* When using spherical stereo, get camera shift without multiview,
+ * leaving stereo to be handled by the engine. */
+ Render *re = engine->re;
+ if (use_spherical_stereo || re == NULL) {
+ return BKE_camera_multiview_shift_x(NULL, camera, NULL);
+ }
+
+ return BKE_camera_multiview_shift_x(&re->r, camera, re->viewname);
+}
+
+void RE_engine_get_camera_model_matrix(RenderEngine *engine,
+ Object *camera,
+ bool use_spherical_stereo,
+ float *r_modelmat)
+{
+ /* When using spherical stereo, get model matrix without multiview,
+ * leaving stereo to be handled by the engine. */
+ Render *re = engine->re;
+ if (use_spherical_stereo || re == NULL) {
+ BKE_camera_multiview_model_matrix(NULL, camera, NULL, (float(*)[4])r_modelmat);
+ }
+ else {
+ BKE_camera_multiview_model_matrix(&re->r, camera, re->viewname, (float(*)[4])r_modelmat);
+ }
+}
+
+bool RE_engine_get_spherical_stereo(RenderEngine *engine, Object *camera)
+{
+ Render *re = engine->re;
+ return BKE_camera_multiview_spherical_stereo(re ? &re->r : NULL, camera) ? 1 : 0;
+}
+
+rcti *RE_engine_get_current_tiles(Render *re, int *r_total_tiles, bool *r_needs_free)
+{
+ static rcti tiles_static[BLENDER_MAX_THREADS];
+ const int allocation_step = BLENDER_MAX_THREADS;
+ int total_tiles = 0;
+ rcti *tiles = tiles_static;
+ int allocation_size = BLENDER_MAX_THREADS;
+
+ BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_READ);
+
+ *r_needs_free = false;
+
+ if (!re->parts || (re->engine && (re->engine->flag & RE_ENGINE_HIGHLIGHT_TILES) == 0)) {
+ *r_total_tiles = 0;
+ BLI_rw_mutex_unlock(&re->partsmutex);
+ return NULL;
+ }
+
+ GHashIterator pa_iter;
+ GHASH_ITER (pa_iter, re->parts) {
+ RenderPart *pa = BLI_ghashIterator_getValue(&pa_iter);
+ if (pa->status == PART_STATUS_IN_PROGRESS) {
+ if (total_tiles >= allocation_size) {
+ /* Just in case we're using crazy network rendering with more
+ * workers than BLENDER_MAX_THREADS.
+ */
+ allocation_size += allocation_step;
+ if (tiles == tiles_static) {
+ /* Can not realloc yet, tiles are pointing to a
+ * stack memory.
+ */
+ tiles = MEM_mallocN(allocation_size * sizeof(rcti), "current engine tiles");
+ }
+ else {
+ tiles = MEM_reallocN(tiles, allocation_size * sizeof(rcti));
+ }
+ *r_needs_free = true;
+ }
+ tiles[total_tiles] = pa->disprect;
+
+ total_tiles++;
+ }
+ }
+ BLI_rw_mutex_unlock(&re->partsmutex);
+ *r_total_tiles = total_tiles;
+ return tiles;
+}
+
+RenderData *RE_engine_get_render_data(Render *re)
+{
+ return &re->r;
+}
+
+/* Depsgraph */
+static void engine_depsgraph_init(RenderEngine *engine, ViewLayer *view_layer)
+{
+ Main *bmain = engine->re->main;
+ Scene *scene = engine->re->scene;
+
+ engine->depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
+ DEG_debug_name_set(engine->depsgraph, "RENDER");
+
+ if (engine->re->r.scemode & R_BUTS_PREVIEW) {
+ Depsgraph *depsgraph = engine->depsgraph;
+ DEG_graph_relations_update(depsgraph);
+ DEG_evaluate_on_framechange(depsgraph, CFRA);
+ DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, true);
+ DEG_ids_clear_recalc(bmain, depsgraph);
+ }
+ else {
+ BKE_scene_graph_update_for_newframe(engine->depsgraph);
+ }
+
+ engine->has_grease_pencil = DRW_render_check_grease_pencil(engine->depsgraph);
+}
+
+static void engine_depsgraph_free(RenderEngine *engine)
+{
+ DEG_graph_free(engine->depsgraph);
+
+ engine->depsgraph = NULL;
+}
+
+void RE_engine_frame_set(RenderEngine *engine, int frame, float subframe)
+{
+ if (!engine->depsgraph) {
+ return;
+ }
+
+ Render *re = engine->re;
+ double cfra = (double)frame + (double)subframe;
+
+ CLAMP(cfra, MINAFRAME, MAXFRAME);
+ BKE_scene_frame_set(re->scene, cfra);
+ BKE_scene_graph_update_for_newframe(engine->depsgraph);
+
+ BKE_scene_camera_switch_update(re->scene);
+}
+
+/* Bake */
+void RE_bake_engine_set_engine_parameters(Render *re, Main *bmain, Scene *scene)
+{
+ re->scene = scene;
+ re->main = bmain;
+ render_copy_renderdata(&re->r, &scene->r);
+}
+
+bool RE_bake_has_engine(Render *re)
+{
+ RenderEngineType *type = RE_engines_find(re->r.engine);
+ return (type->bake != NULL);
+}
+
+bool RE_bake_engine(Render *re,
+ Depsgraph *depsgraph,
+ Object *object,
+ const int object_id,
+ const BakePixel pixel_array[],
+ const BakeImages *bake_images,
+ const int depth,
+ const eScenePassType pass_type,
+ const int pass_filter,
+ float result[])
+{
+ RenderEngineType *type = RE_engines_find(re->r.engine);
+ RenderEngine *engine;
+ bool persistent_data = (re->r.mode & R_PERSISTENT_DATA) != 0;
+
+ /* set render info */
+ re->i.cfra = re->scene->r.cfra;
+ BLI_strncpy(re->i.scene_name, re->scene->id.name + 2, sizeof(re->i.scene_name) - 2);
+
+ /* render */
+ engine = re->engine;
+
+ if (!engine) {
+ engine = RE_engine_create(type);
+ re->engine = engine;
+ }
+
+ engine->flag |= RE_ENGINE_RENDERING;
+
+ /* TODO: actually link to a parent which shouldn't happen */
+ engine->re = re;
+
+ engine->resolution_x = re->winx;
+ engine->resolution_y = re->winy;
+
+ BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE);
+ RE_parts_init(re);
+ engine->tile_x = re->r.tilex;
+ engine->tile_y = re->r.tiley;
+ BLI_rw_mutex_unlock(&re->partsmutex);
+
+ if (type->bake) {
+ engine->depsgraph = depsgraph;
+
+ /* update is only called so we create the engine.session */
+ if (type->update) {
+ type->update(engine, re->main, engine->depsgraph);
+ }
+
+ for (int i = 0; i < bake_images->size; i++) {
+ const BakeImage *image = bake_images->data + i;
+
+ engine->bake.pixels = pixel_array + image->offset;
+ engine->bake.result = result + image->offset * depth;
+ engine->bake.width = image->width;
+ engine->bake.height = image->height;
+ engine->bake.depth = depth;
+ engine->bake.object_id = object_id;
+
+ type->bake(
+ engine, engine->depsgraph, object, pass_type, pass_filter, image->width, image->height);
+
+ memset(&engine->bake, 0, sizeof(engine->bake));
+ }
+
+ engine->depsgraph = NULL;
+ }
+
+ engine->tile_x = 0;
+ engine->tile_y = 0;
+ engine->flag &= ~RE_ENGINE_RENDERING;
+
+ BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE);
+
+ /* re->engine becomes zero if user changed active render engine during render */
+ if (!persistent_data || !re->engine) {
+ RE_engine_free(engine);
+ re->engine = NULL;
+ }
+
+ RE_parts_free(re);
+ BLI_rw_mutex_unlock(&re->partsmutex);
+
+ if (BKE_reports_contain(re->reports, RPT_ERROR)) {
+ G.is_break = true;
+ }
+
+ return true;
+}
+
+/* Render */
+
+static void engine_render_view_layer(Render *re,
+ RenderEngine *engine,
+ ViewLayer *view_layer_iter,
+ const bool use_engine,
+ const bool use_grease_pencil)
+{
+ /* Lock UI so scene can't be edited while we read from it in this render thread. */
+ if (re->draw_lock) {
+ re->draw_lock(re->dlh, 1);
+ }
+
+ /* Create depsgraph with scene evaluated at render resolution. */
+ ViewLayer *view_layer = BLI_findstring(
+ &re->scene->view_layers, view_layer_iter->name, offsetof(ViewLayer, name));
+ engine_depsgraph_init(engine, view_layer);
+
+ /* Sync data to engine, within draw lock so scene data can be accessed safely. */
+ if (use_engine) {
+ if (engine->type->update) {
+ engine->type->update(engine, re->main, engine->depsgraph);
+ }
+ }
+
+ if (re->draw_lock) {
+ re->draw_lock(re->dlh, 0);
+ }
+
+ /* Perform render with engine. */
+ if (use_engine) {
+ if (engine->type->flag & RE_USE_GPU_CONTEXT) {
+ DRW_render_context_enable(engine->re);
+ }
+
+ engine->type->render(engine, engine->depsgraph);
+
+ if (engine->type->flag & RE_USE_GPU_CONTEXT) {
+ DRW_render_context_disable(engine->re);
+ }
+ }
+
+ /* Optionally composite grease pencil over render result. */
+ if (engine->has_grease_pencil && use_grease_pencil && !re->result->do_exr_tile) {
+ /* NOTE: External engine might have been requested to free its
+ * dependency graph, which is only allowed if there is no grease
+ * pencil (pipeline is taking care of that). */
+ if (!RE_engine_test_break(engine) && engine->depsgraph != NULL) {
+ DRW_render_gpencil(engine, engine->depsgraph);
+ }
+ }
+
+ /* Free dependency graph, if engine has not done it already. */
+ engine_depsgraph_free(engine);
+}
+
+int RE_engine_render(Render *re, int do_all)
+{
+ RenderEngineType *type = RE_engines_find(re->r.engine);
+ bool persistent_data = (re->r.mode & R_PERSISTENT_DATA) != 0;
+
+ /* verify if we can render */
+ if (!type->render) {
+ return 0;
+ }
+ if ((re->r.scemode & R_BUTS_PREVIEW) && !(type->flag & RE_USE_PREVIEW)) {
+ return 0;
+ }
+ if (do_all && !(type->flag & RE_USE_POSTPROCESS)) {
+ return 0;
+ }
+ if (!do_all && (type->flag & RE_USE_POSTPROCESS)) {
+ return 0;
+ }
+
+ /* Lock drawing in UI during data phase. */
+ if (re->draw_lock) {
+ re->draw_lock(re->dlh, 1);
+ }
+
+ /* update animation here so any render layer animation is applied before
+ * creating the render result */
+ if ((re->r.scemode & (R_NO_FRAME_UPDATE | R_BUTS_PREVIEW)) == 0) {
+ render_update_anim_renderdata(re, &re->scene->r, &re->scene->view_layers);
+ }
+
+ /* create render result */
+ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+ if (re->result == NULL || !(re->r.scemode & R_BUTS_PREVIEW)) {
+ int savebuffers = RR_USE_MEM;
+
+ if (re->result) {
+ render_result_free(re->result);
+ }
+
+ if ((type->flag & RE_USE_SAVE_BUFFERS) && (re->r.scemode & R_EXR_TILE_FILE)) {
+ savebuffers = RR_USE_EXR;
+ }
+ re->result = render_result_new(re, &re->disprect, 0, savebuffers, RR_ALL_LAYERS, RR_ALL_VIEWS);
+ }
+ BLI_rw_mutex_unlock(&re->resultmutex);
+
+ if (re->result == NULL) {
+ /* Clear UI drawing locks. */
+ if (re->draw_lock) {
+ re->draw_lock(re->dlh, 0);
+ }
+ /* Too small image is handled earlier, here it could only happen if
+ * there was no sufficient memory to allocate all passes.
+ */
+ BKE_report(re->reports, RPT_ERROR, "Failed allocate render result, out of memory");
+ G.is_break = true;
+ return 1;
+ }
+
+ /* set render info */
+ re->i.cfra = re->scene->r.cfra;
+ BLI_strncpy(re->i.scene_name, re->scene->id.name + 2, sizeof(re->i.scene_name));
+
+ /* render */
+ RenderEngine *engine = re->engine;
+
+ if (!engine) {
+ engine = RE_engine_create(type);
+ re->engine = engine;
+ }
+
+ engine->flag |= RE_ENGINE_RENDERING;
+
+ /* TODO: actually link to a parent which shouldn't happen */
+ engine->re = re;
+
+ if (re->flag & R_ANIMATION) {
+ engine->flag |= RE_ENGINE_ANIMATION;
+ }
+ if (re->r.scemode & R_BUTS_PREVIEW) {
+ engine->flag |= RE_ENGINE_PREVIEW;
+ }
+ engine->camera_override = re->camera_override;
+
+ engine->resolution_x = re->winx;
+ engine->resolution_y = re->winy;
+
+ BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE);
+ RE_parts_init(re);
+ engine->tile_x = re->partx;
+ engine->tile_y = re->party;
+ BLI_rw_mutex_unlock(&re->partsmutex);
+
+ if (re->result->do_exr_tile) {
+ render_result_exr_file_begin(re, engine);
+ }
+
+ /* Clear UI drawing locks. */
+ if (re->draw_lock) {
+ re->draw_lock(re->dlh, 0);
+ }
+
+ /* Render view layers. */
+ bool delay_grease_pencil = false;
+
+ if (type->render) {
+ FOREACH_VIEW_LAYER_TO_RENDER_BEGIN (re, view_layer_iter) {
+ engine_render_view_layer(re, engine, view_layer_iter, true, true);
+
+ /* With save buffers there is no render buffer in memory for compositing, delay
+ * grease pencil in that case. */
+ delay_grease_pencil = engine->has_grease_pencil && re->result->do_exr_tile;
+
+ if (RE_engine_test_break(engine)) {
+ break;
+ }
+ }
+ FOREACH_VIEW_LAYER_TO_RENDER_END;
+ }
+
+ /* Clear tile data */
+ engine->tile_x = 0;
+ engine->tile_y = 0;
+ engine->flag &= ~RE_ENGINE_RENDERING;
+
+ render_result_free_list(&engine->fullresult, engine->fullresult.first);
+
+ BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE);
+
+ /* For save buffers, read back from disk. */
+ if (re->result->do_exr_tile) {
+ render_result_exr_file_end(re, engine);
+ }
+
+ /* Perform delayed grease pencil rendering. */
+ if (delay_grease_pencil) {
+ BLI_rw_mutex_unlock(&re->partsmutex);
+
+ FOREACH_VIEW_LAYER_TO_RENDER_BEGIN (re, view_layer_iter) {
+ engine_render_view_layer(re, engine, view_layer_iter, false, true);
+ if (RE_engine_test_break(engine)) {
+ break;
+ }
+ }
+ FOREACH_VIEW_LAYER_TO_RENDER_END;
+
+ BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE);
+ }
+
+ /* re->engine becomes zero if user changed active render engine during render */
+ if (!persistent_data || !re->engine) {
+ RE_engine_free(engine);
+ re->engine = NULL;
+ }
+
+ if (re->r.scemode & R_EXR_CACHE_FILE) {
+ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+ render_result_exr_file_cache_write(re);
+ BLI_rw_mutex_unlock(&re->resultmutex);
+ }
+
+ RE_parts_free(re);
+ BLI_rw_mutex_unlock(&re->partsmutex);
+
+ if (BKE_reports_contain(re->reports, RPT_ERROR)) {
+ G.is_break = true;
+ }
+
+#ifdef WITH_FREESTYLE
+ if (re->r.mode & R_EDGE_FRS) {
+ RE_RenderFreestyleExternal(re);
+ }
+#endif
+
+ return 1;
+}
+
+void RE_engine_update_render_passes(struct RenderEngine *engine,
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ update_render_passes_cb_t callback,
+ void *callback_data)
+{
+ if (!(scene && view_layer && engine && callback && engine->type->update_render_passes)) {
+ return;
+ }
+
+ BLI_mutex_lock(&engine->update_render_passes_mutex);
+
+ engine->update_render_passes_cb = callback;
+ engine->update_render_passes_data = callback_data;
+ engine->type->update_render_passes(engine, scene, view_layer);
+ engine->update_render_passes_cb = NULL;
+ engine->update_render_passes_data = NULL;
+
+ BLI_mutex_unlock(&engine->update_render_passes_mutex);
+}
+
+void RE_engine_register_pass(struct RenderEngine *engine,
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ const char *name,
+ int channels,
+ const char *chanid,
+ eNodeSocketDatatype type)
+{
+ if (!(scene && view_layer && engine && engine->update_render_passes_cb)) {
+ return;
+ }
+
+ engine->update_render_passes_cb(
+ engine->update_render_passes_data, scene, view_layer, name, channels, chanid, type);
+}
+
+void RE_engine_free_blender_memory(RenderEngine *engine)
+{
+ /* Weak way to save memory, but not crash grease pencil.
+ *
+ * TODO(sergey): Find better solution for this.
+ */
+ if (engine->has_grease_pencil) {
+ return;
+ }
+ DEG_graph_free(engine->depsgraph);
+ engine->depsgraph = NULL;
+}
diff --git a/source/tools b/source/tools
-Subproject dc4ccc3bfb646ef2a558bd3565f84080e99b0e8
+Subproject f067d32f4e8c830cfca758a74a49fa39d7f851e