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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_brush.h4
-rw-r--r--source/blender/blenkernel/BKE_customdata.h21
-rw-r--r--source/blender/blenkernel/BKE_data_transfer.h11
-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.h48
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h307
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.cc2
-rw-r--r--source/blender/blenkernel/intern/anim_data.c2
-rw-r--r--source/blender/blenkernel/intern/brush.c174
-rw-r--r--source/blender/blenkernel/intern/collection.c5
-rw-r--r--source/blender/blenkernel/intern/curve_bevel.c2
-rw-r--r--source/blender/blenkernel/intern/customdata.c336
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c7
-rw-r--r--source/blender/blenkernel/intern/idprop_utils.c2
-rw-r--r--source/blender/blenkernel/intern/lib_id.c2
-rw-r--r--source/blender/blenkernel/intern/mesh.c17
-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.c461
-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.c82
-rw-r--r--source/blender/blenkernel/intern/pbvh.c938
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c3972
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h57
-rw-r--r--source/blender/blenkernel/intern/scene.c1
-rw-r--r--source/blender/blenkernel/intern/subdiv_displacement_multires.c1
31 files changed, 5877 insertions, 641 deletions
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index 452a08bc9c8..bf3d45d318c 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -36,6 +36,8 @@ struct Main;
struct Scene;
struct ToolSettings;
struct UnifiedPaintSettings;
+struct DynTopoSettings;
+struct Sculpt;
// enum eCurveMappingPreset;
@@ -151,6 +153,8 @@ void BKE_brush_scale_size(int *r_brush_size,
/* debugging only */
void BKE_brush_debug_print_state(struct Brush *br);
+void BKE_brush_get_dyntopo(struct Brush *brush, struct Sculpt *sd, struct DynTopoSettings *out);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index c4db8ee925e..6db68de8103 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,
@@ -265,6 +271,16 @@ void CustomData_copy_data_named(const struct CustomData *source,
int dest_index,
int count);
void CustomData_copy_elements(int type, void *src_data_ofs, void *dst_data_ofs, int count);
+
+// ignores CD_MESH_ID layer if it exists
+void CustomData_bmesh_swap_data(struct CustomData *source,
+ struct CustomData *dest,
+ void *src_block,
+ void **dest_block);
+
+// simple pointer swap; will unswaps ids if a CD_MESH_ID layer exists
+void CustomData_bmesh_swap_data_simple(CustomData *data, void **block1, void **block2);
+
void CustomData_bmesh_copy_data(const struct CustomData *source,
struct CustomData *dest,
void *src_block,
@@ -593,6 +609,11 @@ void CustomData_blend_write(struct BlendWriter *writer,
struct ID *id);
void CustomData_blend_read(struct BlendDataReader *reader, struct CustomData *data, int count);
+void CustomData_unmark_temporary_nocopy(struct CustomData *data);
+void CustomData_mark_temporary_nocopy(struct CustomData *data);
+
+int CustomData_get_elem_size(CustomDataLayer *layer);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_data_transfer.h b/source/blender/blenkernel/BKE_data_transfer.h
index a2544e43c3d..c45aa307e8f 100644
--- a/source/blender/blenkernel/BKE_data_transfer.h
+++ b/source/blender/blenkernel/BKE_data_transfer.h
@@ -54,9 +54,11 @@ enum {
DT_TYPE_UV = 1 << 24,
DT_TYPE_SHARP_FACE = 1 << 25,
DT_TYPE_FREESTYLE_FACE = 1 << 26,
-#define DT_TYPE_MAX 27
+ DT_TYPE_PROPCOL = 1 << 27,
+#define DT_TYPE_MAX 28
- DT_TYPE_VERT_ALL = DT_TYPE_MDEFORMVERT | DT_TYPE_SHAPEKEY | DT_TYPE_SKIN | DT_TYPE_BWEIGHT_VERT,
+ DT_TYPE_VERT_ALL = DT_TYPE_MDEFORMVERT | DT_TYPE_SHAPEKEY | DT_TYPE_SKIN | DT_TYPE_BWEIGHT_VERT |
+ DT_TYPE_PROPCOL,
DT_TYPE_EDGE_ALL = DT_TYPE_SHARP_EDGE | DT_TYPE_SEAM | DT_TYPE_CREASE | DT_TYPE_BWEIGHT_EDGE |
DT_TYPE_FREESTYLE_EDGE,
DT_TYPE_LOOP_ALL = DT_TYPE_VCOL | DT_TYPE_LNOR | DT_TYPE_UV,
@@ -74,7 +76,7 @@ int BKE_object_data_transfer_dttype_to_cdtype(const int dtdata_type);
int BKE_object_data_transfer_dttype_to_srcdst_index(const int dtdata_type);
#define DT_DATATYPE_IS_VERT(_dt) \
- ELEM(_dt, DT_TYPE_MDEFORMVERT, DT_TYPE_SHAPEKEY, DT_TYPE_SKIN, DT_TYPE_BWEIGHT_VERT)
+ ELEM(_dt, DT_TYPE_MDEFORMVERT, DT_TYPE_SHAPEKEY, DT_TYPE_SKIN, DT_TYPE_BWEIGHT_VERT, DT_TYPE_PROPCOL)
#define DT_DATATYPE_IS_EDGE(_dt) \
ELEM(_dt, \
DT_TYPE_CREASE, \
@@ -94,7 +96,8 @@ enum {
DT_MULTILAYER_INDEX_SHAPEKEY = 1,
DT_MULTILAYER_INDEX_VCOL = 2,
DT_MULTILAYER_INDEX_UV = 3,
- DT_MULTILAYER_INDEX_MAX = 4,
+ DT_MULTILAYER_INDEX_PROPCOL = 4,
+ DT_MULTILAYER_INDEX_MAX = 5,
};
/* Below we keep positive values for real layers idx (generated dynamically). */
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 12560ebed7b..821bf1c4fea 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 11bfc4b2b3a..765f285c324 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 a16822fd7dd..3485bd8ce38 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" {
@@ -154,8 +156,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 73413b61456..1dcd21448df 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -23,9 +23,11 @@
* \ingroup bke
*/
+#include "BKE_pbvh.h"
#include "BLI_bitmap.h"
#include "BLI_utildefines.h"
#include "DNA_brush_enums.h"
+#include "DNA_customdata_types.h"
#include "DNA_object_enums.h"
#ifdef __cplusplus
@@ -342,6 +344,11 @@ typedef struct SculptClothSimulation {
/** #PBVHNode pointer as a key, index in #SculptClothSimulation.node_state as value. */
struct GHash *node_state_index;
eSculptClothNodeSimState *node_state;
+
+ // persistent base customdata layer offsets
+ int cd_pers_co;
+ int cd_pers_no;
+ int cd_pers_disp;
} SculptClothSimulation;
typedef struct SculptPersistentBase {
@@ -360,7 +367,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 +379,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 +405,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
@@ -418,7 +428,7 @@ typedef struct SculptBoundary {
/* Bend Deform type. */
struct {
float (*pivot_rotation_axis)[3];
- float (*pivot_positions)[3];
+ float (*pivot_positions)[4];
} bend;
/* Slide Deform type. */
@@ -440,7 +450,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;
@@ -462,6 +472,12 @@ typedef struct SculptSession {
struct MPoly *mpoly;
struct MLoop *mloop;
+ // only assigned in PBVH_FACES and PBVH_GRIDS
+ CustomData *vdata, *edata, *ldata, *pdata;
+
+ // for grids
+ CustomData temp_vdata, temp_pdata;
+
/* These contain the vertex and poly counts of the final mesh. */
int totvert, totpoly;
@@ -495,8 +511,12 @@ typedef struct SculptSession {
/* BMesh for dynamic topology sculpting */
struct BMesh *bm;
+ int cd_dyn_vert;
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;
@@ -524,9 +544,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.
@@ -548,9 +568,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 */
@@ -612,6 +635,9 @@ typedef struct SculptSession {
*/
char needs_flush_to_id;
+ // id of current stroke, used to detect
+ // if vertex original data needs to be updated
+ int stroke_id;
} SculptSession;
void BKE_sculptsession_free(struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 056a7e2d897..84c46ed5315 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -22,20 +22,65 @@
*/
#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 SculptVertRef {
+ intptr_t i;
+} SculptVertRef;
+
+typedef struct SculptFaceRef {
+ intptr_t i;
+} 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;
+}
+
+typedef struct PBVHTri {
+ int v[3]; // references into PBVHTriBuf->verts
+
+ float no[3];
+ SculptFaceRef f;
+} PBVHTri;
+
+typedef struct PBVHTriBuf {
+ PBVHTri *tris;
+ SculptVertRef *verts;
+ int tottri, totvert;
+ int tris_size, verts_size;
+
+ // private field
+ intptr_t *loops;
+ int totloop, mat_nr;
+ float min[3], max[3];
+} PBVHTriBuf;
+
struct BMLog;
struct BMesh;
+struct BMVert;
+struct BMEdge;
+struct BMFace;
struct CCGElem;
struct CCGKey;
struct CustomData;
+struct TableGSet;
struct DMFlagMat;
struct GPU_PBVH_Buffers;
struct IsectRayPrecalc;
@@ -52,12 +97,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 +197,10 @@ typedef enum {
PBVH_UpdateTopology = 1 << 13,
PBVH_UpdateColor = 1 << 14,
+ PBVH_Delete = 1 << 15,
+ PBVH_UpdateCurvatureDir = 1 << 16,
+ PBVH_UpdateTris = 1 << 17,
+ PBVH_RebuildNodeVerts = 1 << 18
} PBVHNodeFlags;
typedef struct PBVHFrustumPlanes {
@@ -98,6 +221,9 @@ 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);
+PBVHNode *BKE_pbvh_get_node(PBVH *pbvh, int node);
+
/* Building */
PBVH *BKE_pbvh_new(void);
@@ -124,9 +250,27 @@ 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_dyn_vert);
+void BKE_pbvh_update_offsets(PBVH *pbvh,
+ const int cd_vert_node_offset,
+ const int cd_face_node_offset,
+ const int cd_dyn_vert);
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, bool log_undo);
+void BKE_pbvh_update_origcolor_bmesh(PBVH *pbvh, PBVHNode *node);
+void BKE_pbvh_update_origco_bmesh(PBVH *pbvh, PBVHNode *node);
+
+/**
+checks if original data needs to be updated for v, and if so updates it. Stroke_id
+is provided by the sculpt code and is used to detect updates. The reason we do it
+inside the verts and not in the nodes is to allow splitting of the pbvh during the stroke.
+*/
+bool BKE_pbvh_bmesh_check_origdata(PBVH *pbvh, struct BMVert *v, int stroke_id);
+
/* Hierarchical Search in the BVH, two methods:
* - for each hit calling a callback
* - gather nodes in an array (easy to multithread) */
@@ -150,7 +294,8 @@ void BKE_pbvh_raycast(PBVH *pbvh,
void *data,
const float ray_start[3],
const float ray_normal[3],
- bool original);
+ bool original,
+ int stroke_id);
bool BKE_pbvh_node_raycast(PBVH *pbvh,
PBVHNode *node,
@@ -160,11 +305,13 @@ 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,
- float *face_normal);
+ SculptVertRef *active_vertex_index,
+ SculptFaceRef *active_face_grid_index,
+ float *face_normal,
+ int stroke_id);
-bool BKE_pbvh_bmesh_node_raycast_detail(PBVHNode *node,
+bool BKE_pbvh_bmesh_node_raycast_detail(PBVH *pbvh,
+ PBVHNode *node,
const float ray_start[3],
struct IsectRayPrecalc *isect_precalc,
float *depth,
@@ -189,7 +336,8 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *pbvh,
const float ray_start[3],
const float ray_normal[3],
float *depth,
- float *dist_sq);
+ float *dist_sq,
+ int stroke_id);
/* Drawing */
@@ -198,7 +346,8 @@ void BKE_pbvh_draw_cb(PBVH *pbvh,
PBVHFrustumPlanes *update_frustum,
PBVHFrustumPlanes *draw_frustum,
void (*draw_fn)(void *user_data, struct GPU_PBVH_Buffers *buffers),
- void *user_data);
+ void *user_data,
+ bool active_vcol_only);
void BKE_pbvh_draw_debug_cb(
PBVH *pbvh,
@@ -238,20 +387,42 @@ int BKE_pbvh_get_grid_num_faces(const PBVH *pbvh);
/* Only valid for type == PBVH_BMESH */
struct BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh);
-void BKE_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size);
+void BKE_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size, float detail_range);
typedef enum {
PBVH_Subdivide = 1,
PBVH_Collapse = 2,
+ PBVH_Cleanup = 4, // dissolve verts surrounded by either 3 or 4 triangles then triangulate
} PBVHTopologyUpdateMode;
+
+typedef float (*DyntopoMaskCB)(SculptVertRef vertex, void *userdata);
+
bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
PBVHTopologyUpdateMode mode,
const float center[3],
const float view_normal[3],
float radius,
const bool use_frontface,
- const bool use_projected);
-
+ const bool use_projected,
+ int symaxis,
+ bool updatePBVH,
+ DyntopoMaskCB mask_cb,
+ void *mask_cb_data);
+
+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,
+ DyntopoMaskCB mask_cb,
+ void *mask_cb_data);
/* Node Access */
void BKE_pbvh_node_mark_update(PBVHNode *node);
@@ -292,10 +463,14 @@ 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_regen_node_verts(PBVH *pbvh);
+void BKE_pbvh_bmesh_mark_node_regen(PBVH *pbvh, PBVHNode *node);
+
+// now generated PBVHTris
void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh);
/* Update Bounding Box/Redraw and clear flags */
@@ -343,6 +518,7 @@ typedef struct PBVHVertexIter {
int gy;
int i;
int index;
+ SculptVertRef vertex;
bool respect_hide;
/* grid */
@@ -362,10 +538,14 @@ 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_dyn_vert;
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 */
@@ -379,6 +559,8 @@ typedef struct PBVHVertexIter {
bool visible;
} PBVHVertexIter;
+#define BKE_PBVH_DYNVERT(cd_dyn_vert, v) ((MDynTopoVert *)BM_ELEM_CD_GET_VOID_P(v, cd_dyn_vert))
+
void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int mode);
#define BKE_pbvh_vertex_iter_begin(pbvh, node, vi, mode) \
@@ -388,7 +570,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 +589,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 +610,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,22 +619,41 @@ 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); \
+ vi.mask = (float *)BM_ELEM_CD_GET_VOID_P(vi.bm_vert, vi.cd_vert_mask_offset); \
}
#define BKE_pbvh_vertex_iter_end \
@@ -460,14 +662,18 @@ 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);
+
+#define BKE_pbvh_face_index_to_table(pbvh, v) \
+ (BKE_pbvh_type(pbvh) == PBVH_BMESH && v.i != -1 ? BM_elem_index_get((BMFace *)(v.i)) : (v.i))
+SculptFaceRef BKE_pbvh_table_index_to_face(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);
void BKE_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***r_array, int *r_tot);
-void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node,
- int (**r_orco_tris)[3],
- int *r_orco_tris_num,
- float (**r_orco_coords)[3]);
bool BKE_pbvh_node_vert_update_check_any(PBVH *pbvh, PBVHNode *node);
@@ -490,6 +696,45 @@ 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);
+int BKE_pbvh_get_node_id(PBVH *pbvh, PBVHNode *node);
+void BKE_pbvh_set_flat_vcol_shading(PBVH *pbvh, bool value);
+
+#define DYNTOPO_CD_INTERP
+
+void SCULPT_update_flat_vcol_shading(struct Object *ob, struct Scene *scene);
+
+void BKE_pbvh_curvature_update_set(PBVHNode *node, bool state);
+bool BKE_pbvh_curvature_update_get(PBVHNode *node);
+
+int BKE_pbvh_get_totnodes(PBVH *pbvh);
+
+bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node);
+PBVHTriBuf *BKE_pbvh_bmesh_get_tris(PBVH *pbvh, PBVHNode *node);
+void BKE_pbvh_bmesh_free_tris(PBVH *pbvh, PBVHNode *node);
+
+/*recalculates boundary flags for *all* vertices. used by
+ symmetrize.*/
+void BKE_pbvh_recalc_bmesh_boundary(PBVH *pbvh);
+
+void BKE_pbvh_bmesh_remove_face(PBVH *pbvh, struct BMFace *f, bool log_face);
+void BKE_pbvh_bmesh_remove_vertex(PBVH *pbvh, struct BMVert *v, bool log_vert);
+void BKE_pbvh_bmesh_add_face(PBVH *pbvh, struct BMFace *f, bool log_face, bool force_tree_walk);
+
+// note that e_tri and f_example are allowed to be NULL
+struct BMFace *BKE_pbvh_face_create_bmesh(PBVH *pbvh,
+ struct BMVert *v_tri[3],
+ struct BMEdge *e_tri[3],
+ const struct BMFace *f_example);
+
+// if node is NULL, one will be foudn in the pbvh, which potentially can be slow
+struct BMVert *BKE_pbvh_vert_create_bmesh(
+ PBVH *pbvh, float co[3], float no[3], PBVHNode *node, struct BMVert *v_example);
+PBVHNode *BKE_pbvh_node_from_face_bmesh(PBVH *pbvh, struct BMFace *f);
+PBVHNode *BKE_pbvh_node_from_index(PBVH *pbvh, int node_i);
+
+struct BMesh *BKE_pbvh_reorder_bmesh(PBVH *pbvh);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 527996ee46d..1b6de62fecb 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -284,7 +284,7 @@ set(SRC
intern/workspace.c
intern/world.c
intern/writeavi.c
-
+
BKE_DerivedMesh.h
BKE_action.h
BKE_addon.h
diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc
index ba8cf8debe9..5cfd6956272 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.cc
+++ b/source/blender/blenkernel/intern/DerivedMesh.cc
@@ -1141,7 +1141,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
unsupported = true;
}
- if (scene->toolsettings->sculpt->flags & SCULPT_ONLY_DEFORM) {
+ if (scene->toolsettings->sculpt && scene->toolsettings->sculpt->flags & SCULPT_ONLY_DEFORM) {
unsupported |= (mti->type != eModifierTypeType_OnlyDeform);
}
diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c
index 7e4ab754500..21bba9cdb08 100644
--- a/source/blender/blenkernel/intern/anim_data.c
+++ b/source/blender/blenkernel/intern/anim_data.c
@@ -425,7 +425,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 abf7bab7612..bc9677acd03 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -251,6 +251,24 @@ static void brush_blend_read_data(BlendDataReader *reader, ID *id)
{
Brush *brush = (Brush *)id;
+ // detect old file data
+ if (brush->autosmooth_radius_factor == 0.0f) {
+ brush->autosmooth_radius_factor = 1.0f;
+ }
+
+ if (brush->topology_rake_radius_factor == 0.0f) {
+ brush->topology_rake_radius_factor = 1.0f;
+ }
+
+ if (brush->autosmooth_spacing == 0.0f) {
+ brush->autosmooth_spacing = 12;
+ }
+
+ if (brush->topology_rake_spacing == 0.0f) {
+ brush->topology_rake_spacing = 12;
+ brush->topology_rake_projection = 1.0f;
+ }
+
/* Falloff curve. */
BLO_read_data_address(reader, &brush->curve);
@@ -447,7 +465,13 @@ static void brush_defaults(Brush *brush)
FROM_DEFAULT(alpha);
FROM_DEFAULT(hardness);
FROM_DEFAULT(autosmooth_factor);
+ FROM_DEFAULT(autosmooth_projection);
+ FROM_DEFAULT(autosmooth_radius_factor);
+ FROM_DEFAULT(autosmooth_spacing);
FROM_DEFAULT(topology_rake_factor);
+ FROM_DEFAULT(topology_rake_radius_factor);
+ FROM_DEFAULT(topology_rake_projection);
+ FROM_DEFAULT(topology_rake_spacing);
FROM_DEFAULT(crease_pinch_factor);
FROM_DEFAULT(normal_radius_factor);
FROM_DEFAULT(wet_paint_radius_factor);
@@ -478,6 +502,7 @@ static void brush_defaults(Brush *brush)
FROM_DEFAULT(stencil_dimension);
FROM_DEFAULT(mtex);
FROM_DEFAULT(mask_mtex);
+ FROM_DEFAULT(dyntopo);
#undef FROM_DEFAULT
#undef FROM_DEFAULT_PTR
@@ -1649,6 +1674,8 @@ void BKE_brush_debug_print_state(Brush *br)
BR_TEST(plane_offset, f);
BR_TEST(autosmooth_factor, f);
+ BR_TEST(autosmooth_projection, f);
+ BR_TEST(autosmooth_radius_factor, f);
BR_TEST(topology_rake_factor, f);
@@ -1690,6 +1717,8 @@ void BKE_brush_sculpt_reset(Brush *br)
* assign this so logic below can remain the same. */
br->alpha = 0.5f;
+ bool disable_dyntopo = false;
+
/* Brush settings */
switch (br->sculpt_tool) {
case SCULPT_TOOL_DRAW_SHARP:
@@ -1701,11 +1730,16 @@ void BKE_brush_sculpt_reset(Brush *br)
br->curve_preset = BRUSH_CURVE_SMOOTHER;
br->spacing = 10;
br->alpha = 1.0f;
+
+ disable_dyntopo = true;
+
break;
case SCULPT_TOOL_SLIDE_RELAX:
br->spacing = 10;
br->alpha = 1.0f;
br->slide_deform_type = BRUSH_SLIDE_DEFORM_DRAG;
+
+ disable_dyntopo = true;
break;
case SCULPT_TOOL_CLAY:
br->flag |= BRUSH_SIZE_PRESSURE;
@@ -1753,6 +1787,8 @@ void BKE_brush_sculpt_reset(Brush *br)
break;
case SCULPT_TOOL_ROTATE:
br->alpha = 1.0;
+ disable_dyntopo = true;
+
break;
case SCULPT_TOOL_SMOOTH:
br->flag &= ~BRUSH_SPACE_ATTEN;
@@ -1761,10 +1797,14 @@ void BKE_brush_sculpt_reset(Brush *br)
br->surface_smooth_shape_preservation = 0.5f;
br->surface_smooth_current_vertex = 0.5f;
br->surface_smooth_iterations = 4;
+
+ disable_dyntopo = true;
break;
case SCULPT_TOOL_SNAKE_HOOK:
br->alpha = 1.0f;
br->rake_factor = 1.0f;
+ br->dyntopo.inherit = DYNTOPO_INHERIT_BITMASK & ~(DYNTOPO_INHERIT_ALL | DYNTOPO_COLLAPSE);
+ br->dyntopo.flag |= DYNTOPO_COLLAPSE;
break;
case SCULPT_TOOL_THUMB:
br->size = 75;
@@ -1778,6 +1818,8 @@ void BKE_brush_sculpt_reset(Brush *br)
br->flag &= ~BRUSH_ALPHA_PRESSURE;
br->flag &= ~BRUSH_SPACE;
br->flag &= ~BRUSH_SPACE_ATTEN;
+
+ disable_dyntopo = true;
break;
case SCULPT_TOOL_POSE:
br->pose_smooth_iterations = 4;
@@ -1786,18 +1828,24 @@ void BKE_brush_sculpt_reset(Brush *br)
br->flag &= ~BRUSH_ALPHA_PRESSURE;
br->flag &= ~BRUSH_SPACE;
br->flag &= ~BRUSH_SPACE_ATTEN;
+
+ disable_dyntopo = true;
break;
case SCULPT_TOOL_BOUNDARY:
br->flag &= ~BRUSH_ALPHA_PRESSURE;
br->flag &= ~BRUSH_SPACE;
br->flag &= ~BRUSH_SPACE_ATTEN;
br->curve_preset = BRUSH_CURVE_CONSTANT;
+
+ disable_dyntopo = true;
break;
case SCULPT_TOOL_DRAW_FACE_SETS:
br->alpha = 0.5f;
br->flag &= ~BRUSH_ALPHA_PRESSURE;
br->flag &= ~BRUSH_SPACE;
br->flag &= ~BRUSH_SPACE_ATTEN;
+
+ disable_dyntopo = true;
break;
case SCULPT_TOOL_GRAB:
br->alpha = 0.4f;
@@ -1805,6 +1853,8 @@ void BKE_brush_sculpt_reset(Brush *br)
br->flag &= ~BRUSH_ALPHA_PRESSURE;
br->flag &= ~BRUSH_SPACE;
br->flag &= ~BRUSH_SPACE_ATTEN;
+
+ disable_dyntopo = true;
break;
case SCULPT_TOOL_CLOTH:
br->cloth_mass = 1.0f;
@@ -1813,6 +1863,8 @@ void BKE_brush_sculpt_reset(Brush *br)
br->cloth_sim_falloff = 0.75f;
br->cloth_deform_type = BRUSH_CLOTH_DEFORM_DRAG;
br->flag &= ~(BRUSH_ALPHA_PRESSURE | BRUSH_SIZE_PRESSURE);
+
+ disable_dyntopo = true;
break;
case SCULPT_TOOL_LAYER:
br->flag &= ~BRUSH_SPACE_ATTEN;
@@ -1830,6 +1882,8 @@ void BKE_brush_sculpt_reset(Brush *br)
br->density = 1.0f;
br->flag &= ~BRUSH_SPACE_ATTEN;
zero_v3(br->rgb);
+
+ disable_dyntopo = true;
break;
case SCULPT_TOOL_SMEAR:
br->alpha = 1.0f;
@@ -1837,6 +1891,18 @@ void BKE_brush_sculpt_reset(Brush *br)
br->flag &= ~BRUSH_ALPHA_PRESSURE;
br->flag &= ~BRUSH_SPACE_ATTEN;
br->curve_preset = BRUSH_CURVE_SPHERE;
+
+ disable_dyntopo = true;
+ 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;
+
+ disable_dyntopo = true;
break;
case SCULPT_TOOL_DISPLACEMENT_SMEAR:
br->alpha = 1.0f;
@@ -1845,11 +1911,17 @@ void BKE_brush_sculpt_reset(Brush *br)
br->flag &= ~BRUSH_ALPHA_PRESSURE;
br->flag &= ~BRUSH_SPACE_ATTEN;
br->curve_preset = BRUSH_CURVE_SMOOTHER;
+ disable_dyntopo = true;
break;
default:
break;
}
+ if (disable_dyntopo) {
+ // disabled flag is never inherited
+ br->dyntopo.flag |= DYNTOPO_DISABLED;
+ }
+
/* Cursor colors */
/* Default Alpha */
@@ -1906,6 +1978,13 @@ void BKE_brush_sculpt_reset(Brush *br)
break;
case SCULPT_TOOL_SIMPLIFY:
+ //don't use DYNTOPO_INHERIT_BITMASK, we want to include
+ //future bits
+ br->dyntopo.inherit = 0x7FFFFFFF &
+ ~(DYNTOPO_INHERIT_ALL | DYNTOPO_SUBDIVIDE | DYNTOPO_COLLAPSE);
+ br->dyntopo.flag |= DYNTOPO_COLLAPSE | DYNTOPO_SUBDIVIDE;
+ br->autosmooth_factor = 0.02;
+ case SCULPT_TOOL_VCOL_BOUNDARY:
case SCULPT_TOOL_PAINT:
case SCULPT_TOOL_MASK:
case SCULPT_TOOL_DRAW_FACE_SETS:
@@ -2541,3 +2620,98 @@ struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary, bool
return im;
}
+
+void BKE_brush_get_dyntopo(Brush *brush, Sculpt *sd, DynTopoSettings *out)
+{
+ *out = brush->dyntopo;
+
+ // detect unconverted file data
+ if (!out->inherit && !out->detail_range) {
+ // reload default dyntopo settings
+ Brush brush2 = *brush;
+
+ // don't copy heap allocd data
+ brush2.curve = NULL;
+ brush2.icon_imbuf = NULL;
+ brush2.gpencil_settings = NULL;
+ brush2.gradient = NULL;
+ brush2.preview = NULL;
+
+ BKE_brush_sculpt_reset(&brush2);
+
+ brush->dyntopo = *out = brush2.dyntopo;
+
+ brush_free_data((ID *)&brush2);
+ } else if (!out->detail_size) {
+ brush->dyntopo.inherit |= DYNTOPO_INHERIT_DETAIL_SIZE;
+ brush->dyntopo.detail_size = 12.0;
+ }
+
+ int inherit = out->inherit;
+
+ if (inherit & DYNTOPO_INHERIT_ALL) {
+ inherit = 0x7FFFFFFF;
+ }
+
+ if (inherit & DYNTOPO_INHERIT_MODE) {
+ if (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT) {
+ out->mode = DYNTOPO_DETAIL_CONSTANT;
+ }
+ else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
+ out->mode = DYNTOPO_DETAIL_BRUSH;
+ }
+ else if (sd->flags & SCULPT_DYNTOPO_DETAIL_MANUAL) {
+ out->mode = DYNTOPO_DETAIL_MANUAL;
+ }
+ else {
+ out->mode = DYNTOPO_DETAIL_RELATIVE;
+ }
+ }
+
+ if (inherit & DYNTOPO_INHERIT_DETAIL_SIZE) {
+ out->detail_size = sd->detail_size;
+ }
+
+ if (inherit & DYNTOPO_INHERIT_DETAIL_RANGE) {
+ out->detail_range = sd->detail_range;
+ }
+
+ if (inherit & DYNTOPO_INHERIT_DETAIL_PERCENT) {
+ out->detail_percent = sd->detail_percent;
+ }
+
+ if (inherit & DYNTOPO_INHERIT_SPACING) {
+ out->spacing = sd->dyntopo_spacing;
+ }
+
+ if (inherit & DYNTOPO_INHERIT_CONSTANT_DETAIL) {
+ out->constant_detail = sd->constant_detail;
+ }
+
+ if (inherit & DYNTOPO_SUBDIVIDE) {
+ if (sd->flags & SCULPT_DYNTOPO_SUBDIVIDE) {
+ out->flag |= DYNTOPO_SUBDIVIDE;
+ }
+ else {
+ out->flag &= ~DYNTOPO_SUBDIVIDE;
+ }
+ }
+
+ if (inherit & DYNTOPO_COLLAPSE) {
+ if (sd->flags & SCULPT_DYNTOPO_COLLAPSE) {
+ out->flag |= DYNTOPO_COLLAPSE;
+ }
+ else {
+ out->flag &= ~DYNTOPO_COLLAPSE;
+ }
+ }
+
+ if (inherit & DYNTOPO_CLEANUP) {
+ if (sd->flags & SCULPT_DYNTOPO_CLEANUP) {
+ out->flag |= DYNTOPO_CLEANUP;
+ }
+ else {
+ out->flag &= ~DYNTOPO_CLEANUP;
+ }
+ }
+};
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index c354115e030..30198297347 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -689,10 +689,11 @@ static Collection *collection_duplicate_recursive(Main *bmain,
Collection *BKE_collection_duplicate(Main *bmain,
Collection *parent,
Collection *collection,
- eDupli_ID_Flags duplicate_flags,
- eLibIDDuplicateFlags duplicate_options)
+ const uint duplicate_flags_in, //it's not const!! - joeedh
+ const uint duplicate_options)
{
const bool is_subprocess = (duplicate_options & LIB_ID_DUPLICATE_IS_SUBPROCESS) != 0;
+ uint duplicate_flags = duplicate_flags_in;
if (!is_subprocess) {
BKE_main_id_newptr_and_tag_clear(bmain);
diff --git a/source/blender/blenkernel/intern/curve_bevel.c b/source/blender/blenkernel/intern/curve_bevel.c
index d205d8cca46..f853e584537 100644
--- a/source/blender/blenkernel/intern/curve_bevel.c
+++ b/source/blender/blenkernel/intern/curve_bevel.c
@@ -100,7 +100,7 @@ static void curve_bevel_make_extrude_and_fill(const Curve *cu,
* for #Curve.bevresol is 32. */
float *quarter_coords_x = alloca(sizeof(float) * (cu->bevresol + 1));
float *quarter_coords_y = alloca(sizeof(float) * (cu->bevresol + 1));
- bevel_quarter_fill(cu, quarter_coords_x, quarter_coords_y);
+ bevel_quarter_fill((Curve *)cu, quarter_coords_x, quarter_coords_y);
int nr;
if (fill_type == FULL) {
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 7aa9d1958eb..81a63240719 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -35,6 +35,7 @@
#include "DNA_meshdata_types.h"
#include "BLI_bitmap.h"
+#include "BLI_compiler_attrs.h"
#include "BLI_endian_switch.h"
#include "BLI_math.h"
#include "BLI_math_color_blend.h"
@@ -72,6 +73,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)
@@ -1477,6 +1504,92 @@ static bool layerValidate_propfloat2(void *data, const uint totitems, const bool
return has_errors;
}
+static void layerDynTopoVert_copy(const void *source, void *dest, int count)
+{
+ const MDynTopoVert *mv = (MDynTopoVert *)dest;
+
+ memcpy(dest, source, count * sizeof(MDynTopoVert));
+}
+
+static void layerDynTopoVert_interp(
+ const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
+{
+ float co[3], no[3], origmask, color[4];
+ MDynTopoVert *mv = (MDynTopoVert *)dest;
+ float totweight = 0.0f;
+
+ if (count == 0) {
+ memset(mv, 0, sizeof(*mv));
+ return;
+ }
+
+ zero_v3(co);
+ zero_v3(no);
+ origmask = 0.0f;
+ zero_v4(color);
+
+ for (int i = 0; i < count; i++) {
+ MDynTopoVert *mv2 = (MDynTopoVert *)sources[i];
+ float w;
+
+ if (i == 0) { // copy flag from first source
+ mv->flag = mv2->flag;
+ mv->stroke_id = mv2->stroke_id;
+ }
+
+ if (sub_weights) {
+ w = sub_weights[i];
+ }
+ else {
+ w = 1.0f;
+ }
+
+ madd_v3_v3fl(co, mv2->origco, w);
+ madd_v3_v3fl(no, mv2->origno, w);
+ madd_v4_v4fl(color, mv2->origcolor, w);
+ origmask += mv2->origmask * w;
+
+ totweight += w;
+ }
+
+ float mul = 1.0f / totweight;
+
+ mul_v3_fl(co, mul);
+ mul_v3_fl(no, mul);
+ mul_v4_fl(color, mul);
+ origmask *= mul;
+
+ copy_v3_v3(mv->origco, co);
+ copy_v3_v3(mv->origno, no);
+ copy_v4_v4(mv->origcolor, color);
+
+ mv->origmask = origmask;
+}
+
+static void layerCopy_noop(const void *UNUSED(source), void *UNUSED(dest), int UNUSED(count))
+{
+ // do nothing
+}
+
+static void layerInterp_noop(const void **UNUSED(sources),
+ const float *UNUSED(weights),
+ const float *UNUSED(sub_weights),
+ int UNUSED(count),
+ void *UNUSED(dest))
+{
+ // do nothing
+}
+
+static void layerDefault_mesh_id(void *data, int count)
+{
+ int *val = (int *)data;
+
+ for (int i = 0; i < count; i++) {
+ // val[i] = -1;
+ val[i] = 0;
+ }
+}
+
static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 0: CD_MVERT */
{sizeof(MVert), "MVert", 1, NULL, NULL, NULL, NULL, NULL, NULL},
@@ -1858,7 +1971,24 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
NULL,
NULL,
NULL},
-};
+ /* 51 CD_DYNTOPO_VERT */
+ {sizeof(MDynTopoVert),
+ "MDynTopoVert",
+ 1,
+ NULL, // flag singleton layer
+ layerDynTopoVert_copy,
+ NULL,
+ layerDynTopoVert_interp},
+ /*52 CD_MESH_ID */
+ {sizeof(unsigned int),
+ "MIntProperty",
+ 1,
+ NULL, // flag singleton layer
+ layerCopy_propInt,
+ NULL,
+ layerInterp_noop,
+ NULL,
+ layerDefault_mesh_id}};
static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
/* 0-4 */ "CDMVert",
@@ -1914,7 +2044,7 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
"CDPropFloat3",
"CDPropFloat2",
"CDPropBoolean",
-};
+ "CDDyntopoVert"};
const CustomData_MeshMasks CD_MASK_BAREMESH = {
.vmask = CD_MASK_MVERT | CD_MASK_BWEIGHT,
@@ -1963,7 +2093,8 @@ const CustomData_MeshMasks CD_MASK_DERIVEDMESH = {
};
const CustomData_MeshMasks CD_MASK_BMESH = {
.vmask = (CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
- CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR),
+ CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR |
+ CD_MASK_DYNTOPO_VERT),
.emask = (CD_MASK_BWEIGHT | CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
.fmask = 0,
.lmask = (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
@@ -2011,6 +2142,11 @@ static const LayerTypeInfo *layerType_getInfo(int type)
return &LAYERTYPEINFO[type];
}
+int CustomData_get_elem_size(CustomDataLayer *layer)
+{
+ return layerType_getInfo(layer->type)->size;
+}
+
static const char *layerType_getName(int type)
{
if (type < 0 || type >= CD_NUMTYPES) {
@@ -2095,6 +2231,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,
@@ -2836,6 +2992,24 @@ bool CustomData_is_referenced_layer(struct CustomData *data, int type)
return (layer->flag & CD_FLAG_NOFREE) != 0;
}
+void CustomData_unmark_temporary_nocopy(CustomData *data)
+{
+ for (int i = 0; i < data->totlayer; i++) {
+ if (data->layers[i].flag & CD_FLAG_TEMPORARY) {
+ data->layers[i].flag &= ~CD_FLAG_NOCOPY;
+ }
+ }
+}
+
+void CustomData_mark_temporary_nocopy(CustomData *data)
+{
+ for (int i = 0; i < data->totlayer; i++) {
+ if (data->layers[i].flag & CD_FLAG_TEMPORARY) {
+ data->layers[i].flag |= CD_FLAG_NOCOPY;
+ }
+ }
+}
+
void CustomData_free_temporary(CustomData *data, int totelem)
{
int i, j;
@@ -3692,6 +3866,12 @@ static void CustomData_bmesh_set_default_n(CustomData *data, void **block, int n
int offset = data->layers[n].offset;
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[n].type);
+ /* can't allow this to be called on CD_MESH_ID */
+
+ if (data->layers[n].type == CD_MESH_ID) {
+ return;
+ }
+
if (typeInfo->set_default) {
typeInfo->set_default(POINTER_OFFSET(*block, offset), 1);
}
@@ -3711,6 +3891,95 @@ void CustomData_bmesh_set_default(CustomData *data, void **block)
}
}
+void CustomData_bmesh_swap_data_simple(CustomData *data, void **block1, void **block2)
+{
+ int cd_id = data->typemap[CD_MESH_ID];
+ cd_id = cd_id >= 0 ? data->layers[cd_id].offset : -1;
+
+ void *tmp = *block1;
+ *block1 = *block2;
+ *block2 = tmp;
+
+ // unswap ids if they exist
+ if (cd_id != -1 && *block1 && *block2) {
+ int *id1 = (int *)(((char *)*block1) + cd_id);
+ int *id2 = (int *)(((char *)*block2) + cd_id);
+
+ tmp = *id1;
+ *id1 = *id2;
+ *id2 = tmp;
+ }
+}
+
+void CustomData_bmesh_swap_data(CustomData *source,
+ CustomData *dest,
+ void *src_block,
+ void **dest_block)
+{
+ int src_i = 0;
+ int dest_i = 0;
+ int dest_i_start = 0;
+
+ if (*dest_block == NULL) {
+ CustomData_bmesh_alloc_block(dest, dest_block);
+
+ if (*dest_block) {
+ memset(*dest_block, 0, dest->totsize);
+ CustomData_bmesh_set_default(dest, dest_block);
+ }
+ }
+
+ for (src_i = 0; src_i < source->totlayer; src_i++) {
+ /* find the first dest layer with type >= the source type
+ * (this should work because layers are ordered by type)
+ */
+ while (dest_i_start < dest->totlayer &&
+ dest->layers[dest_i_start].type < source->layers[src_i].type) {
+ dest_i_start++;
+ }
+
+ if (source->layers[src_i].type == CD_MESH_ID) {
+ // do not swap ids
+ continue;
+ }
+
+ /* if there are no more dest layers, we're done */
+ if (dest_i_start >= dest->totlayer) {
+ return;
+ }
+
+ dest_i = dest_i_start;
+
+ while (dest_i < dest->totlayer && dest->layers[dest_i].type == source->layers[src_i].type) {
+ /* if we found a matching layer, copy the data */
+ if (dest->layers[dest_i].type == source->layers[src_i].type &&
+ STREQ(dest->layers[dest_i].name, source->layers[src_i].name)) {
+ void *src_data = POINTER_OFFSET(src_block, source->layers[src_i].offset);
+ void *dest_data = POINTER_OFFSET(*dest_block, dest->layers[dest_i].offset);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(source->layers[src_i].type);
+ const uint size = typeInfo->size;
+
+ // swap data
+ char *bsrc = (char *)src_data;
+ char *bdst = (char *)dest_data;
+
+ for (int j = 0; j < size; j++) {
+ char t = *bsrc;
+ *bsrc = *bdst;
+ *bdst = t;
+
+ bsrc++;
+ bdst++;
+ }
+
+ break;
+ }
+
+ dest_i++;
+ }
+ }
+}
+
void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source,
CustomData *dest,
void *src_block,
@@ -3728,50 +3997,59 @@ void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source,
}
}
+ for (int dest_i = 0; dest_i < dest->totlayer; dest_i++) {
+ CustomData_bmesh_set_default_n(dest, dest_block, dest_i);
+ dest_i++;
+ }
+
/* copies a layer at a time */
- int dest_i = 0;
+ int dest_i_start = 0;
+
for (int src_i = 0; src_i < source->totlayer; src_i++) {
/* find the first dest layer with type >= the source type
* (this should work because layers are ordered by type)
*/
- while (dest_i < dest->totlayer && dest->layers[dest_i].type < source->layers[src_i].type) {
- CustomData_bmesh_set_default_n(dest, dest_block, dest_i);
- dest_i++;
+ while (dest_i_start < dest->totlayer &&
+ dest->layers[dest_i_start].type < source->layers[src_i].type) {
+ dest_i_start++;
}
/* if there are no more dest layers, we're done */
- if (dest_i >= dest->totlayer) {
+ if (dest_i_start >= dest->totlayer) {
return;
}
- /* if we found a matching layer, copy the data */
- if (dest->layers[dest_i].type == source->layers[src_i].type &&
- STREQ(dest->layers[dest_i].name, source->layers[src_i].name)) {
- if (no_mask || ((CD_TYPE_AS_MASK(dest->layers[dest_i].type) & mask_exclude) == 0)) {
- const void *src_data = POINTER_OFFSET(src_block, source->layers[src_i].offset);
- void *dest_data = POINTER_OFFSET(*dest_block, dest->layers[dest_i].offset);
- const LayerTypeInfo *typeInfo = layerType_getInfo(source->layers[src_i].type);
- if (typeInfo->copy) {
- typeInfo->copy(src_data, dest_data, 1);
- }
- else {
- memcpy(dest_data, src_data, typeInfo->size);
+ int dest_i = dest_i_start;
+
+ /*Previously this code was only checking one source layer against one destination.
+ Now it scans all the layers of that type. - joeedh
+ */
+ while (dest_i < dest->totlayer && dest->layers[dest_i].type == source->layers[src_i].type) {
+ /* if we found a matching layer, copy the data */
+ if (STREQ(dest->layers[dest_i].name, source->layers[src_i].name)) {
+ if (no_mask || ((CD_TYPE_AS_MASK(dest->layers[dest_i].type) & mask_exclude) == 0)) {
+ if (dest->layers[dest_i].flag & CD_FLAG_ELEM_NOCOPY) {
+ break;
+ }
+
+ const void *src_data = POINTER_OFFSET(src_block, source->layers[src_i].offset);
+ void *dest_data = POINTER_OFFSET(*dest_block, dest->layers[dest_i].offset);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(source->layers[src_i].type);
+ if (typeInfo->copy) {
+ typeInfo->copy(src_data, dest_data, 1);
+ }
+ else {
+ memcpy(dest_data, src_data, typeInfo->size);
+ }
}
+
+ break;
}
- /* if there are multiple source & dest layers of the same type,
- * we don't want to copy all source layers to the same dest, so
- * increment dest_i
- */
dest_i++;
}
}
-
- while (dest_i < dest->totlayer) {
- CustomData_bmesh_set_default_n(dest, dest_block, dest_i);
- dest_i++;
- }
}
void CustomData_bmesh_copy_data(const CustomData *source,
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index 605061570b8..371dd97e8bc 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -150,6 +150,7 @@ bool BKE_object_data_transfer_get_dttypes_capacity(const int dtdata_types,
case DT_TYPE_UV:
ret = true;
break;
+ case DT_TYPE_PROPCOL:
case DT_TYPE_VCOL:
*r_advanced_mixing = true;
*r_threshold = true;
@@ -230,12 +231,12 @@ int BKE_object_data_transfer_dttype_to_cdtype(const int dtdata_type)
return CD_FAKE_SHARP;
case DT_TYPE_FREESTYLE_FACE:
return CD_FREESTYLE_FACE;
-
case DT_TYPE_VCOL:
return CD_MLOOPCOL;
case DT_TYPE_LNOR:
return CD_FAKE_LNOR;
-
+ case DT_TYPE_PROPCOL:
+ return CD_PROP_COLOR;
default:
BLI_assert(0);
}
@@ -253,6 +254,8 @@ int BKE_object_data_transfer_dttype_to_srcdst_index(const int dtdata_type)
return DT_MULTILAYER_INDEX_UV;
case DT_TYPE_VCOL:
return DT_MULTILAYER_INDEX_VCOL;
+ case DT_TYPE_PROPCOL:
+ return DT_MULTILAYER_INDEX_PROPCOL;
default:
return DT_MULTILAYER_INDEX_INVALID;
}
diff --git a/source/blender/blenkernel/intern/idprop_utils.c b/source/blender/blenkernel/intern/idprop_utils.c
index 0cc212e1880..e427de44ce5 100644
--- a/source/blender/blenkernel/intern/idprop_utils.c
+++ b/source/blender/blenkernel/intern/idprop_utils.c
@@ -184,7 +184,7 @@ static void idp_repr_fn_recursive(struct ReprState *state, const IDProperty *pro
const ID *id = prop->data.pointer;
if (id != NULL) {
STR_APPEND_STR("bpy.data.");
- STR_APPEND_STR(BKE_idtype_idcode_to_name_plural(GS(id->name)));
+ STR_APPEND_STR(BKE_idtype_idcode_to_name_plural((short)GS(id->name)));
STR_APPEND_STR("[");
STR_APPEND_STR_QUOTE(id->name + 2);
STR_APPEND_STR("]");
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index 62d29188c5a..aad98eeebab 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -644,7 +644,7 @@ ID *BKE_id_copy(Main *bmain, const ID *id)
* Invokes the appropriate copy method for the block and returns the result in
* newid, unless test. Returns true if the block can be copied.
*/
-ID *BKE_id_copy_for_duplicate(Main *bmain, ID *id, const eDupli_ID_Flags duplicate_flags)
+ID *BKE_id_copy_for_duplicate(Main *bmain, ID *id, const uint duplicate_flags)
{
if (id == NULL) {
return id;
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index b463d903303..c8bf485dade 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -1035,14 +1035,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((Object *)ob, bm, me, convert_params);
return bm;
}
@@ -1052,7 +1053,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,
@@ -1068,8 +1070,13 @@ 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);
- BKE_mesh_copy_parameters_for_eval(mesh, me_settings);
+
+ BM_mesh_bm_to_me(NULL, NULL, bm, mesh, params);
+
+ if (me_settings) {
+ BKE_mesh_copy_parameters_for_eval(mesh, me_settings);
+ }
+
return mesh;
}
diff --git a/source/blender/blenkernel/intern/mesh_mirror.c b/source/blender/blenkernel/intern/mesh_mirror.c
index 9aeaa1ada52..d00378911b1 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){
@@ -207,7 +211,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 5a90d1f6ea5..f02b54506fb 100644
--- a/source/blender/blenkernel/intern/mesh_remesh_voxel.c
+++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.c
@@ -441,7 +441,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 54f0da30a2b..ad53f29f3f6 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,461 @@ 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;
+}
+
+//#define LIMIT_MAX_DISPLACEMENT
+
+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;
+ BMesh *bm = tdata->bm;
+ MultiResSpace op = tdata->bmop;
+ BMFace *f = bm->ftable[pidx];
+ int gridSize = tdata->gridSize;
+
+ int S, x, y;
+
+ BMLoop *l;
+
+#ifdef LIMIT_MAX_DISPLACEMENT
+ 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);
+#endif
+
+ l = f->l_first;
+ S = 0;
+ do {
+ MDisps *mdisp = BM_ELEM_CD_GET_VOID_P(l, cd_mdisps_off);
+ float(*dispgrid)[3] = NULL;
+
+ dispgrid = mdisp->disps;
+
+#ifdef LIMIT_MAX_DISPLACEMENT
+ /*try to limit numerical instability by clamping max displacement*/
+
+ float maxlen = len_v3v3(l->v->co, cent) * 15.0f;
+ maxlen = MAX2(maxlen, 0.00001f);
+#endif
+
+ 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);
+#ifdef LIMIT_MAX_DISPLACEMENT
+ if (len > maxlen) {
+ mul_v3_fl(data, maxlen / len);
+ }
+ else if (isnan(len)) {
+ zero_v3(data);
+ }
+#else
+ if (isnan(len)) {
+ zero_v3(data);
+ }
+#endif
+ break;
+ }
+ }
+ }
+
+ S++;
+ l = l->next;
+ } while (l != f->l_first);
+}
+
+/* The original version of this function was broken (and subsequently removed)
+ because it didn't properly set the subdivision level; it also used the old
+ multires system. The new subdiv API is now used instead.
+ */
+void BKE_multires_bmesh_space_set(Object *ob, BMesh *bm, int mode)
+{
+ if (!bm->totface || !CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
+ return;
+ }
+
+ // get multires settings
+ 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;
+ }
+
+ // cache multires settings in bmesh
+ bm->multiresSpace = mode;
+
+ // create temporary mesh structure
+ 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;
+
+ BM_mesh_bm_to_me_for_eval(bm, me, &extra);
+ SubdivSettings settings2;
+
+ // copy the settings and then set subdivision level to max
+ MultiresModifierData mmdcpy = *mmd;
+ mmdcpy.lvl = mmdcpy.sculptlvl = mmdcpy.renderlvl = mmdcpy.totlvl;
+
+ // set up subdivision surface
+ 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);
+
+ // create a fake object with .sculpt set to 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;
+ int totpoly = bm->totface;
+
+ // force paranoia recalc of indices and 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];
+
+ int cd_disp_off = CustomData_get_offset(&bm->ldata, CD_MDISPS);
+
+ BMFace *f;
+ BMIter iter;
+ i = 0;
+
+ /*check that all grids are allocated and also set some indices*/
+ 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);
+
+ /* allocate new disps, this can happen with newly created faces */
+ if (!mdisp->disps) {
+ multires_reallocate_mdisps(1, mdisp, mmd->totlvl);
+ }
+
+ l->head.index = i;
+
+ if (f->len != 4) {
+ i++;
+ }
+ }
+
+ if (f->len == 4) {
+ i++;
+ }
+ }
+
+ // do the space conversion
+
+ TaskParallelSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = CCG_TASK_LIMIT;
+
+ MultiresThreadedData data = {
+ .bmop = mode,
+ .sd = sd,
+ .lvl = mmd->totlvl,
+ .bm = bm,
+ .cd_mdisps_off = cd_disp_off,
+ .gridSize = gridSize,
+ };
+
+ BLI_task_parallel_range(0, totpoly, &data, multires_bmesh_space_set_cb, &settings);
+
+ 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 +1679,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 +1795,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 +1804,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 9fb158d2f84..e0557922068 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 501e3f27389..2b73be61259 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 1af66fa090b..934d5f75dcf 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -51,6 +51,7 @@
#include "BKE_context.h"
#include "BKE_crazyspace.h"
#include "BKE_deform.h"
+#include "BKE_global.h"
#include "BKE_gpencil.h"
#include "BKE_idtype.h"
#include "BKE_image.h"
@@ -67,6 +68,7 @@
#include "BKE_pbvh.h"
#include "BKE_subdiv_ccg.h"
#include "BKE_subsurf.h"
+#include "BKE_undo_system.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -77,6 +79,11 @@
#include "bmesh.h"
+// XXX todo: work our bad module cross ref
+void SCULPT_dynamic_topology_sync_layers(Object *ob, Mesh *me);
+void SCULPT_on_sculptsession_bmesh_free(SculptSession *ss);
+void SCULPT_reorder_bmesh(SculptSession *ss);
+
static void palette_init_data(ID *id)
{
Palette *palette = (Palette *)id;
@@ -1077,7 +1084,7 @@ bool BKE_paint_ensure(ToolSettings *ts, struct Paint **r_paint)
paint->symmetry_flags |= PAINT_SYMM_X;
/* Make sure at least dyntopo subdivision is enabled */
- data->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE;
+ data->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE | SCULPT_DYNTOPO_CLEANUP;
}
else if ((GpPaint **)r_paint == &ts->gp_paint) {
GpPaint *data = MEM_callocN(sizeof(*data), __func__);
@@ -1377,15 +1384,12 @@ static void sculptsession_bm_to_me_update_data_only(Object *ob, bool reorder)
if (ss->bm) {
if (ob->data) {
- BMIter iter;
- BMFace *efa;
- BM_ITER_MESH (efa, &iter, ss->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_set(efa, BM_ELEM_SMOOTH, ss->bm_smooth_shading);
- }
- if (reorder) {
+ if (reorder && ss->bm_log) {
BM_log_mesh_elems_reorder(ss->bm, ss->bm_log);
}
+
BM_mesh_bm_to_me(NULL,
+ NULL,
ss->bm,
ob->data,
(&(struct BMeshToMeshParams){
@@ -1468,7 +1472,14 @@ void BKE_sculptsession_free(Object *ob)
if (ob && ob->sculpt) {
SculptSession *ss = ob->sculpt;
+ if (ss->bm_log && BM_log_free(ss->bm_log, true)) {
+ ss->bm_log = NULL;
+ }
+
+ /*try to save current mesh*/
if (ss->bm) {
+ SCULPT_on_sculptsession_bmesh_free(ss);
+
BKE_sculptsession_bm_to_me(ob, true);
BM_mesh_free(ss->bm);
}
@@ -1484,10 +1495,6 @@ void BKE_sculptsession_free(Object *ob)
MEM_SAFE_FREE(ss->vemap);
MEM_SAFE_FREE(ss->vemap_mem);
- if (ss->bm_log) {
- BM_log_free(ss->bm_log);
- }
-
MEM_SAFE_FREE(ss->texcache);
if (ss->tex_pool) {
@@ -1623,7 +1630,7 @@ static void sculpt_update_object(Depsgraph *depsgraph,
Scene *scene = DEG_get_input_scene(depsgraph);
Sculpt *sd = scene->toolsettings->sculpt;
SculptSession *ss = ob->sculpt;
- const Mesh *me = BKE_object_get_original_mesh(ob);
+ Mesh *me = BKE_object_get_original_mesh(ob);
MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
const bool use_face_sets = (ob->mode & OB_MODE_SCULPT) != 0;
@@ -1676,6 +1683,11 @@ static void sculpt_update_object(Depsgraph *depsgraph,
ss->multires.level = 0;
ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
ss->vcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
+
+ ss->vdata = &me->vdata;
+ ss->edata = &me->edata;
+ ss->ldata = &me->ldata;
+ ss->pdata = &me->pdata;
}
/* Sculpt Face Sets. */
@@ -1795,6 +1807,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 +1824,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_ALL_MODES);
+ 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);
}
@@ -1900,9 +1915,20 @@ void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene)
if (!sd->detail_size) {
sd->detail_size = 12;
}
+
+ if (!sd->detail_range) {
+ sd->detail_range = 0.4f;
+ sd->flags |= SCULPT_DYNTOPO_CLEANUP; // should really do this in do_versions_290.c
+ }
+
if (!sd->detail_percent) {
sd->detail_percent = 25;
}
+
+ if (!sd->dyntopo_spacing) {
+ sd->dyntopo_spacing = 25;
+ }
+
if (sd->constant_detail == 0.0f) {
sd->constant_detail = 3.0f;
}
@@ -2101,9 +2127,11 @@ 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_dyn_vert);
pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
pbvh_show_face_sets_set(pbvh, false);
+
return pbvh;
}
@@ -2174,6 +2202,8 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
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 +2213,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,12 +2225,21 @@ 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;
}
if (ob->sculpt->bm != NULL) {
/* Sculpting on a BMesh (dynamic-topology) gets a special PBVH. */
pbvh = build_pbvh_for_dynamic_topology(ob);
+
+ ob->sculpt->pbvh = pbvh;
+ // reorder mesh elements to improve memory cache performance
+ SCULPT_reorder_bmesh(ob->sculpt);
}
else {
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
@@ -2213,6 +2254,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 461ffa7765e..1e0b547e778 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -30,6 +30,8 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
#include "BKE_ccg.h"
#include "BKE_mesh.h" /* for BKE_mesh_calc_normals */
@@ -49,7 +51,8 @@
#include <limits.h>
-#define LEAF_LIMIT 10000
+#define LEAF_LIMIT 4000
+#define LEAF_DEPTH_LIMIT 18
//#define PERFCNTRS
@@ -247,6 +250,14 @@ void pbvh_grow_nodes(PBVH *pbvh, int totnode)
}
pbvh->totnode = totnode;
+
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *node = pbvh->nodes + i;
+
+ if (!node->id) {
+ node->id = ++pbvh->idgen;
+ }
+ }
}
/* Add a vertex to the map, with a positive value for unique vertices and
@@ -475,13 +486,15 @@ static bool leaf_needs_material_split(PBVH *pbvh, int offset, int count)
* offset and start indicate a range in the array of primitive indices
*/
-static void build_sub(PBVH *pbvh, int node_index, BB *cb, BBC *prim_bbc, int offset, int count)
+static void build_sub(
+ PBVH *pbvh, int node_index, BB *cb, BBC *prim_bbc, int offset, int count, int depth)
{
int end;
BB cb_backing;
/* Decide whether this is a leaf or not */
- const bool below_leaf_limit = count <= pbvh->leaf_limit;
+ const bool below_leaf_limit = count <= pbvh->leaf_limit || depth >= pbvh->depth_limit;
+
if (below_leaf_limit) {
if (!leaf_needs_material_split(pbvh, offset, count)) {
build_leaf(pbvh, node_index, prim_bbc, offset, count);
@@ -521,13 +534,20 @@ static void build_sub(PBVH *pbvh, int node_index, BB *cb, BBC *prim_bbc, int off
}
/* Build children */
- build_sub(pbvh, pbvh->nodes[node_index].children_offset, NULL, prim_bbc, offset, end - offset);
+ build_sub(pbvh,
+ pbvh->nodes[node_index].children_offset,
+ NULL,
+ prim_bbc,
+ offset,
+ end - offset,
+ depth + 1);
build_sub(pbvh,
pbvh->nodes[node_index].children_offset + 1,
NULL,
prim_bbc,
end,
- offset + count - end);
+ offset + count - end,
+ depth + 1);
}
static void pbvh_build(PBVH *pbvh, BB *cb, BBC *prim_bbc, int totprim)
@@ -552,7 +572,7 @@ static void pbvh_build(PBVH *pbvh, BB *cb, BBC *prim_bbc, int totprim)
}
pbvh->totnode = 1;
- build_sub(pbvh, 0, cb, prim_bbc, 0, totprim);
+ build_sub(pbvh, 0, cb, prim_bbc, 0, totprim, 0);
}
/**
@@ -585,6 +605,8 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
pbvh->vert_bitmap = BLI_BITMAP_NEW(totvert, "bvh->vert_bitmap");
pbvh->totvert = totvert;
pbvh->leaf_limit = LEAF_LIMIT;
+ pbvh->depth_limit = LEAF_DEPTH_LIMIT;
+
pbvh->vdata = vdata;
pbvh->ldata = ldata;
pbvh->pdata = pdata;
@@ -640,6 +662,7 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
pbvh->gridkey = *key;
pbvh->grid_hidden = grid_hidden;
pbvh->leaf_limit = max_ii(LEAF_LIMIT / (gridsize * gridsize), 1);
+ pbvh->depth_limit = LEAF_DEPTH_LIMIT;
BB cb;
BB_reset(&cb);
@@ -682,9 +705,8 @@ void BKE_pbvh_free(PBVH *pbvh)
PBVHNode *node = &pbvh->nodes[i];
if (node->flag & PBVH_Leaf) {
- if (node->draw_buffers) {
- GPU_pbvh_buffers_free(node->draw_buffers);
- }
+ pbvh_free_all_draw_buffers(node);
+
if (node->vert_indices) {
MEM_freeN((void *)node->vert_indices);
}
@@ -692,14 +714,22 @@ 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);
+ }
+
+ if (node->tribuf) {
+ BKE_pbvh_bmesh_free_tris(pbvh, node);
}
+
+#ifdef PROXY_ADVANCED
+ BKE_pbvh_free_proxyarray(pbvh, node);
+#endif
}
}
@@ -1014,6 +1044,8 @@ typedef struct PBVHUpdateData {
float (*vnors)[3];
int flag;
bool show_sculpt_face_sets;
+ bool flat_vcol_shading;
+ bool active_vcol_only;
} PBVHUpdateData;
static void pbvh_update_normals_accum_task_cb(void *__restrict userdata,
@@ -1270,6 +1302,8 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
PBVHNode *node = data->nodes[n];
if (node->flag & PBVH_RebuildDrawBuffers) {
+ node->updategen++;
+
switch (pbvh->type) {
case PBVH_GRIDS:
node->draw_buffers = GPU_pbvh_grid_buffers_build(node->totprim, pbvh->grid_hidden);
@@ -1285,14 +1319,29 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
node->totprim,
pbvh->mesh);
break;
- case PBVH_BMESH:
- node->draw_buffers = GPU_pbvh_bmesh_buffers_build(pbvh->flags &
- PBVH_DYNTOPO_SMOOTH_SHADING);
+ case PBVH_BMESH: {
+ BKE_pbvh_bmesh_check_tris(pbvh, node);
+
+ node->tot_mat_draw_buffers = node->tot_tri_buffers;
+
+ if (node->tot_tri_buffers) {
+ node->mat_draw_buffers = MEM_malloc_arrayN(
+ node->tot_tri_buffers, sizeof(void *), "node->mat_draw_buffers");
+ }
+
+ for (int i = 0; i < node->tot_tri_buffers; i++) {
+ node->mat_draw_buffers[i] = GPU_pbvh_bmesh_buffers_build(pbvh->flags &
+ PBVH_DYNTOPO_SMOOTH_SHADING);
+ }
+
break;
+ }
}
}
if (node->flag & PBVH_UpdateDrawBuffers) {
+ node->updategen++;
+
const int update_flags = pbvh_get_buffers_update_flags(pbvh);
switch (pbvh->type) {
case PBVH_GRIDS:
@@ -1320,44 +1369,133 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
update_flags);
break;
case PBVH_BMESH:
- GPU_pbvh_bmesh_buffers_update(node->draw_buffers,
- pbvh->bm,
- node->bm_faces,
- node->bm_unique_verts,
- node->bm_other_verts,
- update_flags);
+ if (BKE_pbvh_bmesh_check_tris(pbvh, node)) {
+ pbvh_free_all_draw_buffers(node);
+ node->tot_mat_draw_buffers = node->tot_tri_buffers;
+
+ if (node->tot_tri_buffers) {
+ node->mat_draw_buffers = MEM_malloc_arrayN(
+ node->tot_tri_buffers, sizeof(void *), "node->mat_draw_buffers");
+
+ for (int i = 0; i < node->tot_tri_buffers; i++) {
+ node->mat_draw_buffers[i] = GPU_pbvh_bmesh_buffers_build(
+ pbvh->flags & PBVH_DYNTOPO_SMOOTH_SHADING);
+ }
+ }
+ }
+
+ for (int i = 0; i < node->tot_mat_draw_buffers; i++) {
+ if (i >= node->tot_tri_buffers) {
+ printf("pbvh corruption!\n");
+ continue;
+ }
+
+ GPU_pbvh_bmesh_buffers_update(node->mat_draw_buffers[i],
+ pbvh->bm,
+ node->bm_faces,
+ node->bm_unique_verts,
+ node->bm_other_verts,
+ node->tri_buffers + i,
+ update_flags,
+ pbvh->cd_vert_node_offset,
+ pbvh->face_sets_color_seed,
+ pbvh->face_sets_color_default,
+ data->flat_vcol_shading,
+ data->active_vcol_only,
+ node->tri_buffers[i].mat_nr);
+ }
break;
}
}
}
-static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode, int update_flag)
+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;
+}
+
+void pbvh_free_all_draw_buffers(PBVHNode *node)
+{
+ if (node->draw_buffers) {
+ GPU_pbvh_buffers_free(node->draw_buffers);
+ node->draw_buffers = NULL;
+ }
+
+ for (int i = 0; i < node->tot_mat_draw_buffers; i++) {
+ GPU_pbvh_buffers_free(node->mat_draw_buffers[i]);
+ }
+
+ MEM_SAFE_FREE(node->mat_draw_buffers);
+
+ node->mat_draw_buffers = NULL;
+ node->tot_mat_draw_buffers = 0;
+}
+
+void pbvh_update_free_all_draw_buffers(PBVH *pbvh, PBVHNode *node)
+{
+ if (pbvh->type == PBVH_GRIDS) {
+ GPU_pbvh_grid_buffers_update_free(
+ node->draw_buffers, pbvh->grid_flag_mats, node->prim_indices);
+ }
+ else if (pbvh->type == PBVH_BMESH) {
+ for (int i = 0; i < node->tot_mat_draw_buffers; i++) {
+ GPU_pbvh_bmesh_buffers_update_free(node->mat_draw_buffers[i]);
+ }
+ }
+}
+
+static void pbvh_update_draw_buffers(
+ PBVH *pbvh, PBVHNode **nodes, int totnode, int update_flag, bool active_vcol_only)
{
if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(pbvh->type, PBVH_GRIDS, PBVH_BMESH)) {
/* Free buffers uses OpenGL, so not in parallel. */
for (int n = 0; n < totnode; n++) {
PBVHNode *node = nodes[n];
if (node->flag & PBVH_RebuildDrawBuffers) {
- GPU_pbvh_buffers_free(node->draw_buffers);
- node->draw_buffers = NULL;
+ pbvh_free_all_draw_buffers(node);
}
- else if ((node->flag & PBVH_UpdateDrawBuffers) && node->draw_buffers) {
- if (pbvh->type == PBVH_GRIDS) {
- GPU_pbvh_grid_buffers_update_free(
- node->draw_buffers, pbvh->grid_flag_mats, node->prim_indices);
- }
- else if (pbvh->type == PBVH_BMESH) {
- GPU_pbvh_bmesh_buffers_update_free(node->draw_buffers);
- }
+ else if ((node->flag & PBVH_UpdateDrawBuffers)) {
+ pbvh_update_free_all_draw_buffers(pbvh, node);
}
}
}
+ 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, active_vcol_only);
+
/* Parallel creation and update of draw buffers. */
- PBVHUpdateData data = {
- .pbvh = pbvh,
- .nodes = nodes,
- };
+ PBVHUpdateData data = {.pbvh = pbvh,
+ .nodes = nodes,
+ .flat_vcol_shading = pbvh->flat_vcol_shading,
+ .active_vcol_only = active_vcol_only};
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
@@ -1368,7 +1506,13 @@ static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode,
if (node->flag & PBVH_UpdateDrawBuffers) {
/* Flush buffers uses OpenGL, so not in parallel. */
- GPU_pbvh_buffers_update_flush(node->draw_buffers);
+ if (node->draw_buffers) {
+ GPU_pbvh_buffers_update_flush(node->draw_buffers);
+ }
+
+ for (int i = 0; i < node->tot_mat_draw_buffers; i++) {
+ GPU_pbvh_buffers_update_flush(node->mat_draw_buffers[i]);
+ }
}
node->flag &= ~(PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers);
@@ -1407,6 +1551,46 @@ 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_vcol_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_UNIQUE) {
+ MDynTopoVert *mv = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, vd.bm_vert);
+ float *c2 = BM_ELEM_CD_GET_VOID_P(vd.bm_vert, pbvh->cd_vcol_offset);
+
+ copy_v4_v4(mv->origcolor, c2);
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void BKE_pbvh_update_origco_bmesh(PBVH *pbvh, PBVHNode *node)
+{
+ PBVHVertexIter vd;
+
+ if (!pbvh->bm || pbvh->cd_dyn_vert < 0) {
+ return;
+ }
+
+ BKE_pbvh_vertex_iter_begin (pbvh, node, vd, PBVH_ITER_UNIQUE) {
+ MDynTopoVert *mv = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, vd.bm_vert);
+
+ copy_v3_v3(mv->origco, vd.bm_vert->co);
+ copy_v3_v3(mv->origno, vd.bm_vert->no);
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
void BKE_pbvh_update_bounds(PBVH *pbvh, int flag)
{
if (!pbvh->nodes) {
@@ -1509,28 +1693,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);
}
@@ -1732,7 +1916,7 @@ BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh)
void BKE_pbvh_node_mark_update(PBVHNode *node)
{
node->flag |= PBVH_UpdateNormals | PBVH_UpdateBB | PBVH_UpdateOriginalBB |
- PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
+ PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw | PBVH_UpdateCurvatureDir;
}
void BKE_pbvh_node_mark_update_mask(PBVHNode *node)
@@ -1748,12 +1932,13 @@ void BKE_pbvh_node_mark_update_color(PBVHNode *node)
void BKE_pbvh_node_mark_update_visibility(PBVHNode *node)
{
node->flag |= PBVH_UpdateVisibility | PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers |
- PBVH_UpdateRedraw;
+ PBVH_UpdateRedraw | PBVH_UpdateCurvatureDir;
}
void BKE_pbvh_node_mark_rebuild_draw(PBVHNode *node)
{
- node->flag |= PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
+ node->flag |= PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw |
+ PBVH_UpdateCurvatureDir;
}
void BKE_pbvh_node_mark_redraw(PBVHNode *node)
@@ -1763,7 +1948,27 @@ void BKE_pbvh_node_mark_redraw(PBVHNode *node)
void BKE_pbvh_node_mark_normals_update(PBVHNode *node)
{
- node->flag |= PBVH_UpdateNormals;
+ node->flag |= PBVH_UpdateNormals | PBVH_UpdateCurvatureDir;
+}
+
+void BKE_pbvh_node_mark_curvature_update(PBVHNode *node)
+{
+ node->flag |= PBVH_UpdateCurvatureDir;
+}
+
+void BKE_pbvh_curvature_update_set(PBVHNode *node, bool state)
+{
+ if (state) {
+ node->flag |= PBVH_UpdateCurvatureDir;
+ }
+ else {
+ node->flag &= ~PBVH_UpdateCurvatureDir;
+ }
+}
+
+bool BKE_pbvh_curvature_update_get(PBVHNode *node)
+{
+ return node->flag & PBVH_UpdateCurvatureDir;
}
void BKE_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden)
@@ -1854,9 +2059,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;
@@ -1944,16 +2162,6 @@ void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *pro
}
}
-void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node,
- int (**r_orco_tris)[3],
- int *r_orco_tris_num,
- float (**r_orco_coords)[3])
-{
- *r_orco_tris = node->bm_ortri;
- *r_orco_tris_num = node->bm_tot_ortri;
- *r_orco_coords = node->bm_orco;
-}
-
/**
* \note doing a full search on all vertices here seems expensive,
* however this is important to avoid having to recalculate bound-box & sync the buffers to the
@@ -1982,6 +2190,7 @@ bool BKE_pbvh_node_vert_update_check_any(PBVH *pbvh, PBVHNode *node)
typedef struct {
struct IsectRayAABB_Precalc ray;
bool original;
+ int stroke_id;
} RaycastData;
static bool ray_aabb_intersect(PBVHNode *node, void *data_v)
@@ -2008,12 +2217,14 @@ void BKE_pbvh_raycast(PBVH *pbvh,
void *data,
const float ray_start[3],
const float ray_normal[3],
- bool original)
+ bool original,
+ int stroke_id)
{
RaycastData rcd;
isect_ray_aabb_v3_precalc(&rcd.ray, ray_start, ray_normal);
rcd.original = original;
+ rcd.stroke_id = stroke_id;
BKE_pbvh_search_callback_occluded(pbvh, ray_aabb_intersect, &rcd, cb, data);
}
@@ -2136,8 +2347,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;
@@ -2186,8 +2397,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;
}
}
}
@@ -2204,8 +2415,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;
@@ -2271,13 +2482,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;
}
}
}
@@ -2299,9 +2511,10 @@ 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,
- float *face_normal)
+ SculptVertRef *active_vertex_index,
+ SculptFaceRef *active_face_grid_index,
+ float *face_normal,
+ int stroke_id)
{
bool hit = false;
@@ -2335,15 +2548,19 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh,
face_normal);
break;
case PBVH_BMESH:
- BM_mesh_elem_index_ensure(pbvh->bm, BM_VERT);
- hit = pbvh_bmesh_node_raycast(node,
+ // BM_mesh_elem_index_ensure(pbvh->bm, BM_VERT);
+
+ hit = pbvh_bmesh_node_raycast(pbvh,
+ node,
ray_start,
ray_normal,
isect_precalc,
depth,
use_origco,
active_vertex_index,
- face_normal);
+ active_face_grid_index,
+ face_normal,
+ stroke_id);
break;
}
@@ -2558,7 +2775,8 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *pbvh,
const float ray_start[3],
const float ray_normal[3],
float *depth,
- float *dist_sq)
+ float *dist_sq,
+ int stroke_id)
{
bool hit = false;
@@ -2577,7 +2795,7 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *pbvh,
break;
case PBVH_BMESH:
hit = pbvh_bmesh_node_nearest_to_ray(
- node, ray_start, ray_normal, depth, dist_sq, use_origco);
+ pbvh, node, ray_start, ray_normal, depth, dist_sq, use_origco, stroke_id);
break;
}
@@ -2708,7 +2926,8 @@ void BKE_pbvh_draw_cb(PBVH *pbvh,
PBVHFrustumPlanes *update_frustum,
PBVHFrustumPlanes *draw_frustum,
void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers),
- void *user_data)
+ void *user_data,
+ bool active_vcol_only)
{
PBVHNode **nodes;
int totnode;
@@ -2731,7 +2950,7 @@ void BKE_pbvh_draw_cb(PBVH *pbvh,
/* Update draw buffers. */
if (totnode != 0 && (update_flag & (PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers))) {
- pbvh_update_draw_buffers(pbvh, nodes, totnode, update_flag);
+ pbvh_update_draw_buffers(pbvh, nodes, totnode, update_flag, active_vcol_only);
}
MEM_SAFE_FREE(nodes);
@@ -2742,7 +2961,13 @@ void BKE_pbvh_draw_cb(PBVH *pbvh,
for (int i = 0; i < totnode; i++) {
PBVHNode *node = nodes[i];
if (!(node->flag & PBVH_FullyHidden)) {
- draw_fn(user_data, node->draw_buffers);
+ if (node->draw_buffers) {
+ draw_fn(user_data, node->draw_buffers);
+ }
+
+ for (int i = 0; i < node->tot_mat_draw_buffers; i++) {
+ draw_fn(user_data, node->mat_draw_buffers[i]);
+ }
}
}
@@ -2757,7 +2982,9 @@ void BKE_pbvh_draw_debug_cb(
for (int a = 0; a < pbvh->totnode; a++) {
PBVHNode *node = &pbvh->nodes[a];
- draw_fn(user_data, node->vb.bmin, node->vb.bmax, node->flag);
+ int num = a + node->updategen;
+
+ draw_fn(&num, node->vb.bmin, node->vb.bmax, node->flag);
}
}
@@ -2873,7 +3100,7 @@ void BKE_pbvh_node_free_proxies(PBVHNode *node)
node->proxies[p].co = NULL;
}
- MEM_freeN(node->proxies);
+ MEM_SAFE_FREE(node->proxies);
node->proxies = NULL;
node->proxy_count = 0;
@@ -2910,9 +3137,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;
}
@@ -2938,8 +3179,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) {
@@ -2967,9 +3211,17 @@ 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;
+
+ vi->cd_dyn_vert = CustomData_get_offset(vi->bm_vdata, CD_DYNTOPO_VERT);
+
+ // 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);
}
@@ -2999,6 +3251,26 @@ bool pbvh_has_mask(const 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);
+}
+
+SculptFaceRef BKE_pbvh_table_index_to_face(PBVH *pbvh, int idx)
+{
+ if (pbvh->type == PBVH_BMESH) {
+ SculptFaceRef ref = {(intptr_t)pbvh->bm->ftable[idx]};
+ return ref;
+ }
+
+ return BKE_pbvh_make_fref(idx);
+}
+
bool pbvh_has_face_sets(PBVH *pbvh)
{
switch (pbvh->type) {
@@ -3007,7 +3279,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;
@@ -3039,12 +3311,13 @@ void BKE_pbvh_get_frustum_planes(PBVH *pbvh, PBVHFrustumPlanes *planes)
}
}
+#include "BKE_global.h"
void BKE_pbvh_parallel_range_settings(TaskParallelSettings *settings,
bool use_threading,
int totnode)
{
memset(settings, 0, sizeof(*settings));
- settings->use_threading = use_threading && totnode > 1;
+ settings->use_threading = use_threading && totnode > 1 && G.debug_value != 890;
}
MVert *BKE_pbvh_get_verts(const PBVH *pbvh)
@@ -3067,3 +3340,494 @@ 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);
+}
+
+int BKE_pbvh_get_totnodes(PBVH *pbvh)
+{
+ return pbvh->totnode;
+}
+
+int BKE_pbvh_get_node_id(PBVH *pbvh, PBVHNode *node)
+{
+ return node->id;
+}
+
+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);
+}
+
+PBVHNode *BKE_pbvh_node_from_index(PBVH *pbvh, int node_i)
+{
+ return pbvh->nodes + node_i;
+}
+
+#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
+
+/* 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);
+ }
+}
+
+PBVHNode *BKE_pbvh_get_node(PBVH *pbvh, int node)
+{
+ return pbvh->nodes + node;
+}
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index d3d7f02ecad..20629e51186 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -18,14 +18,42 @@
* \ingroup bli
*/
+/*
+
+TODO:
+
+Convergence improvements:
+1. DONE: Limit number of edges processed per run.
+2. DONE: Scale split steps by ratio of long to short edges to
+ prevent runaway tesselation.
+3. DONE: Detect and dissolve three and four valence vertices that are surrounded by
+ all tris.
+4. DONE: Use different (coarser) brush spacing for applying dyntopo
+
+Drawing improvements:
+4. PARTIAL DONE: Build and cache vertex index buffers, to reduce GPU bandwidth
+
+Topology rake:
+5. DONE: Enable new curvature topology rake code and add to UI.
+6. DONE: 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 "atomic_ops.h"
+
+#include "DNA_material_types.h"
#include "BKE_DerivedMesh.h"
#include "BKE_ccg.h"
@@ -36,17 +64,104 @@
#include "bmesh.h"
#include "pbvh_intern.h"
+#define DYNTOPO_MAX_ITER 4096
+
+#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
+
+/* 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.1f
+
+// recursion depth to start applying front face test
+#define DEPTH_START_LIMIT 5
+
+//#define FANCY_EDGE_WEIGHTS
+#define SKINNY_EDGE_FIX
+
+// slightly relax geometry by this factor along surface tangents
+// to improve convergence of remesher
+#define DYNTOPO_SAFE_SMOOTH_FAC 0.05f
+
#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
+static void check_nodes(PBVH *pbvh)
+{
+#if 0
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *node = pbvh->nodes + i;
+ BMVert *v;
+ BMFace *f;
+
+ if (!(node->flag & PBVH_Leaf)) {
+ continue;
+ }
+
+ TGSET_ITER (v, node->bm_unique_verts) {
+ if (v->head.htype > 8) {
+ printf("corruption in pbvh! bm_unique_verts\n");
+ }
+ }
+ TGSET_ITER_END;
+
+ TGSET_ITER (v, node->bm_other_verts) {
+ if (v->head.htype > 8) {
+ printf("corruption in pbvh! bm_other_verts\n");
+ }
+ }
+ TGSET_ITER_END;
+
+ TGSET_ITER (f, node->bm_faces) {
+ if (f->head.htype > 8) {
+ printf("corruption in pbvh! bm_faces\n");
+ }
+ }
+ TGSET_ITER_END;
+ }
+#endif
+}
+
+void pbvh_bmesh_check_nodes(PBVH *pbvh)
+{
+ check_nodes(pbvh);
+}
/**
* 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).
@@ -59,6 +174,8 @@
// #define USE_VERIFY
+#define DYNTOPO_MASK(cd_mask_offset, v) BM_ELEM_CD_GET_FLOAT(v, cd_mask_offset)
+
#ifdef USE_VERIFY
static void pbvh_bmesh_verify(PBVH *pbvh);
#endif
@@ -118,6 +235,46 @@ static void pbvh_bmesh_verify(PBVH *pbvh);
} \
((void)0)
+BLI_INLINE void surface_smooth_v_safe(BMVert *v)
+{
+ float co[3];
+ float tan[3];
+ float tot = 0.0;
+
+ zero_v3(co);
+
+ // this is a manual edge walk
+
+ BMEdge *e = v->e;
+ if (!e) {
+ return;
+ }
+
+ do {
+ BMVert *v2 = e->v1 == v ? e->v2 : e->v1;
+
+ sub_v3_v3v3(tan, v2->co, v->co);
+ float d = dot_v3v3(tan, v->no);
+
+ madd_v3_v3fl(tan, v->no, -d * 0.99f);
+ add_v3_v3(co, tan);
+ tot += 1.0f;
+ e = v == e->v1 ? e->v1_disk_link.next : e->v2_disk_link.next;
+ } while (e != v->e);
+
+ if (tot == 0.0f) {
+ return;
+ }
+
+ mul_v3_fl(co, 1.0f / tot);
+ float x = v->co[0], y = v->co[1], z = v->co[2];
+
+ // conflicts here should be pretty rare.
+ atomic_cas_float(&v->co[0], x, x + co[0] * DYNTOPO_SAFE_SMOOTH_FAC);
+ atomic_cas_float(&v->co[1], y, y + co[1] * DYNTOPO_SAFE_SMOOTH_FAC);
+ atomic_cas_float(&v->co[2], z, z + co[2] * DYNTOPO_SAFE_SMOOTH_FAC);
+}
+
static void bm_edges_from_tri(BMesh *bm, BMVert *v_tri[3], BMEdge *e_tri[3])
{
e_tri[0] = BM_edge_create(bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE);
@@ -201,21 +358,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 +381,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 +398,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 +409,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 | PBVH_UpdateCurvatureDir | PBVH_UpdateTris;
+
+ if (add_orco) {
+ BKE_pbvh_bmesh_check_tris(pbvh, 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,83 +464,96 @@ 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) {
MEM_freeN(n->layer_disp);
}
+ if (n->tribuf) {
+ BKE_pbvh_bmesh_free_tris(pbvh, n);
+ n->tribuf = NULL;
+ }
+
n->bm_faces = NULL;
n->bm_unique_verts = NULL;
n->bm_other_verts = NULL;
n->layer_disp = NULL;
- if (n->draw_buffers) {
- GPU_pbvh_buffers_free(n->draw_buffers);
- n->draw_buffers = NULL;
- }
+ pbvh_free_all_draw_buffers(n);
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 +565,21 @@ 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);
+
+ check_nodes(pbvh);
+
if (bm_faces_size <= pbvh->leaf_limit) {
/* Node limit not exceeded */
return false;
@@ -394,10 +588,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,13 +615,17 @@ 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, false, 0);
MEM_freeN(bbc_array);
+ check_nodes(pbvh);
+
return true;
}
@@ -477,18 +685,25 @@ 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,
int node_index,
const float co[3],
const float no[3],
+ BMVert *v_example,
const int cd_vert_mask_offset)
{
PBVHNode *node = &pbvh->nodes[node_index];
@@ -496,19 +711,39 @@ static BMVert *pbvh_bmesh_vert_create(PBVH *pbvh,
BLI_assert((pbvh->totnode == 1 || node_index) && node_index <= pbvh->totnode);
/* avoid initializing customdata because its quite involved */
- BMVert *v = BM_vert_create(pbvh->bm, co, NULL, BM_CREATE_SKIP_CD);
- CustomData_bmesh_set_default(&pbvh->bm->vdata, &v->head.data);
+ BMVert *v = BM_vert_create(pbvh->bm, co, NULL, BM_CREATE_NOP);
+
+ if (v_example) {
+ v->head.hflag = v_example->head.hflag;
+
+ CustomData_bmesh_copy_data(
+ &pbvh->bm->vdata, &pbvh->bm->vdata, v_example->head.data, &v->head.data);
+
+ /* This value is logged below */
+ copy_v3_v3(v->no, no);
+
+ // keep MDynTopoVert copied from v_example as-is
+ }
+ else {
+ MDynTopoVert *mv = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v);
+
+ copy_v3_v3(mv->origco, co);
+ copy_v3_v3(mv->origno, no);
+ mv->origmask = 0.0f;
+ mv->flag = 0;
- /* This value is logged below */
- copy_v3_v3(v->no, no);
+ /* 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;
+ node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB | PBVH_UpdateTris;
/* 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;
}
@@ -516,30 +751,196 @@ static BMVert *pbvh_bmesh_vert_create(PBVH *pbvh,
/**
* \note Callers are responsible for checking if the face exists before adding.
*/
-static BMFace *pbvh_bmesh_face_create(
- PBVH *pbvh, int node_index, BMVert *v_tri[3], BMEdge *e_tri[3], const BMFace *f_example)
+static BMFace *pbvh_bmesh_face_create(PBVH *pbvh,
+ int node_index,
+ BMVert *v_tri[3],
+ BMEdge *e_tri[3],
+ const BMFace *f_example,
+ bool ensure_verts,
+ bool log_face)
{
PBVHNode *node = &pbvh->nodes[node_index];
/* ensure we never add existing face */
BLI_assert(!BM_face_exists(v_tri, 3));
- BMFace *f = BM_face_create(pbvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP);
- f->head.hflag = f_example->head.hflag;
+ BMFace *f;
+
+ if (!e_tri) {
+ f = BM_face_create_verts(pbvh->bm, v_tri, 3, f_example, BM_CREATE_NOP, true);
+ }
+ else {
+ f = BM_face_create(pbvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP);
+ }
+
+ if (f_example) {
+ 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 */
- node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals;
+ node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals | PBVH_UpdateTris;
node->flag &= ~PBVH_FullyHidden;
/* Log the new face */
- BM_log_face_added(pbvh->bm_log, f);
+ if (log_face) {
+ BM_log_face_added(pbvh->bm_log, f);
+ }
+
+ int cd_vert_node = pbvh->cd_vert_node_offset;
+
+ if (ensure_verts) {
+ BMLoop *l = f->l_first;
+ do {
+ if (BM_ELEM_CD_GET_INT(l->v, cd_vert_node) == DYNTOPO_NODE_NONE) {
+ BLI_table_gset_add(node->bm_unique_verts, l->v);
+ BM_ELEM_CD_SET_INT(l->v, cd_vert_node, node_index);
+
+ node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB | PBVH_UpdateTris;
+ }
+ else {
+ BLI_table_gset_add(node->bm_other_verts, l->v);
+ }
+
+ l = l->next;
+ } while (l != f->l_first);
+ }
return f;
}
+BMVert *BKE_pbvh_vert_create_bmesh(
+ PBVH *pbvh, float co[3], float no[3], PBVHNode *node, BMVert *v_example)
+{
+ if (!node) {
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *node2 = pbvh->nodes + i;
+
+ if (!(node2->flag & PBVH_Leaf)) {
+ continue;
+ }
+
+ // ensure we have at least some node somewhere picked
+ node = node2;
+
+ bool ok = true;
+
+ for (int j = 0; j < 3; j++) {
+ if (co[j] < node2->vb.bmin[j] || co[j] >= node2->vb.bmax[j]) {
+ continue;
+ }
+ }
+
+ if (ok) {
+ break;
+ }
+ }
+ }
+
+ BMVert *v;
+
+ if (!node) {
+ printf("possible pbvh error\n");
+ v = BM_vert_create(pbvh->bm, co, v_example, BM_CREATE_NOP);
+ BM_ELEM_CD_SET_INT(v, pbvh->cd_vert_node_offset, DYNTOPO_NODE_NONE);
+
+ MDynTopoVert *mv = BM_ELEM_CD_GET_VOID_P(v, pbvh->cd_dyn_vert);
+
+ copy_v3_v3(mv->origco, co);
+
+ return v;
+ }
+
+ return pbvh_bmesh_vert_create(
+ pbvh, node - pbvh->nodes, co, no, v_example, pbvh->cd_vert_mask_offset);
+}
+
+PBVHNode *BKE_pbvh_node_from_face_bmesh(PBVH *pbvh, BMFace *f)
+{
+ return pbvh->nodes + BM_ELEM_CD_GET_INT(f, pbvh->cd_face_node_offset);
+}
+
+BMFace *BKE_pbvh_face_create_bmesh(PBVH *pbvh,
+ BMVert *v_tri[3],
+ BMEdge *e_tri[3],
+ const BMFace *f_example)
+{
+ int ni = DYNTOPO_NODE_NONE;
+
+ for (int i = 0; i < 3; i++) {
+ BMVert *v = v_tri[i];
+ BMLoop *l;
+ BMIter iter;
+
+ BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
+ int ni2 = BM_ELEM_CD_GET_INT(l->f, pbvh->cd_face_node_offset);
+ if (ni2 != DYNTOPO_NODE_NONE) {
+ ni = ni2;
+ break;
+ }
+ }
+ }
+
+ if (ni == DYNTOPO_NODE_NONE) {
+ BMFace *f;
+
+ // no existing nodes? find one
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *node = pbvh->nodes + i;
+
+ if (!(node->flag & PBVH_Leaf)) {
+ continue;
+ }
+
+ for (int j = 0; j < 3; j++) {
+ BMVert *v = v_tri[j];
+
+ bool ok = true;
+
+ for (int k = 0; k < 3; k++) {
+ if (v->co[k] < node->vb.bmin[k] || v->co[k] >= node->vb.bmax[k]) {
+ ok = false;
+ }
+ }
+
+ if (ok &&
+ (ni == DYNTOPO_NODE_NONE || BLI_table_gset_len(node->bm_faces) < pbvh->leaf_limit)) {
+ ni = i;
+ break;
+ }
+ }
+
+ if (ni != DYNTOPO_NODE_NONE) {
+ break;
+ }
+ }
+
+ if (ni == DYNTOPO_NODE_NONE) {
+ // empty pbvh?
+ printf("possibly pbvh error\n");
+
+ if (e_tri) {
+ f = BM_face_create_verts(pbvh->bm, v_tri, 3, f_example, BM_CREATE_NOP, true);
+ }
+ else {
+ f = BM_face_create(pbvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP);
+ }
+
+ if (f_example) {
+ f->head.hflag = f_example->head.hflag;
+ }
+
+ BM_ELEM_CD_SET_INT(f, pbvh->cd_face_node_offset, DYNTOPO_NODE_NONE);
+
+ return f;
+ }
+ }
+
+ return pbvh_bmesh_face_create(pbvh, ni, v_tri, e_tri, f_example, true, true);
+}
+
/* Return the number of faces in 'node' that use vertex 'v' */
#if 0
static int pbvh_bmesh_node_vert_use_count(PBVH *pbvh, PBVHNode *node, BMVert *v)
@@ -606,30 +1007,72 @@ 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;
}
+static bool pbvh_bmesh_vert_relink(PBVH *pbvh, BMVert *v)
+{
+ const int cd_vert_node = pbvh->cd_vert_node_offset;
+ const int cd_face_node = pbvh->cd_face_node_offset;
+
+ BMFace *f;
+ BLI_assert(BM_ELEM_CD_GET_INT(v, cd_vert_node) == DYNTOPO_NODE_NONE);
+
+ bool added = false;
+
+ BM_FACES_OF_VERT_ITER_BEGIN (f, v) {
+ const int ni = BM_ELEM_CD_GET_INT(f, cd_face_node);
+
+ if (ni == DYNTOPO_NODE_NONE) {
+ continue;
+ }
+
+ PBVHNode *node = pbvh->nodes + ni;
+
+ if (BM_ELEM_CD_GET_INT(v, cd_vert_node) == DYNTOPO_NODE_NONE) {
+ BLI_table_gset_add(node->bm_unique_verts, v);
+ BM_ELEM_CD_SET_INT(v, cd_vert_node, ni);
+ }
+ else {
+ BLI_table_gset_add(node->bm_other_verts, v);
+ }
+ }
+ BM_FACES_OF_VERT_ITER_END;
+
+ return added;
+}
+
static void pbvh_bmesh_vert_remove(PBVH *pbvh, BMVert *v)
{
/* never match for first time */
int f_node_index_prev = DYNTOPO_NODE_NONE;
+ const int updateflag = PBVH_UpdateDrawBuffers | PBVH_UpdateBB | PBVH_UpdateTris |
+ PBVH_UpdateNormals;
PBVHNode *v_node = pbvh_bmesh_node_from_vert(pbvh, v);
- BLI_gset_remove(v_node->bm_unique_verts, v, NULL);
+
+ if (v_node) {
+ BLI_table_gset_remove(v_node->bm_unique_verts, v, NULL);
+ v_node->flag |= updateflag;
+ }
+
BM_ELEM_CD_SET_INT(v, pbvh->cd_vert_node_offset, DYNTOPO_NODE_NONE);
/* Have to check each neighboring face's node */
@@ -637,62 +1080,268 @@ 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;
PBVHNode *f_node = &pbvh->nodes[f_node_index];
- f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
+ f_node->flag |= updateflag;
/* 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;
}
-static void pbvh_bmesh_face_remove(PBVH *pbvh, BMFace *f)
+static void pbvh_bmesh_face_remove(PBVH *pbvh, BMFace *f, bool log_face, bool check_verts)
{
PBVHNode *f_node = pbvh_bmesh_node_from_face(pbvh, f);
+ if (!f_node || !(f_node->flag & PBVH_Leaf)) {
+ 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);
- BMLoop *l_iter = l_first;
- 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)) {
- /* Find a different node that uses 'v' */
- PBVHNode *new_node;
+ if (check_verts) {
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter = l_first;
+ do {
+ BMVert *v = l_iter->v;
+ if (pbvh_bmesh_node_vert_use_count_is_equal(pbvh, f_node, v, 1)) {
+ if (BLI_table_gset_haskey(f_node->bm_unique_verts, v)) {
+ /* Find a different node that uses 'v' */
+ PBVHNode *new_node;
- new_node = pbvh_bmesh_vert_other_node_find(pbvh, v);
- BLI_assert(new_node || BM_vert_face_count_is_equal(v, 1));
+ new_node = pbvh_bmesh_vert_other_node_find(pbvh, v);
+ BLI_assert(new_node || BM_vert_face_count_is_equal(v, 1));
- if (new_node) {
- pbvh_bmesh_vert_ownership_transfer(pbvh, new_node, v);
+ if (new_node) {
+ pbvh_bmesh_vert_ownership_transfer(pbvh, new_node, v);
+ }
+ }
+ else {
+ /* Remove from other verts */
+ BLI_table_gset_remove(f_node->bm_other_verts, v, NULL);
}
}
- else {
- /* Remove from other verts */
- BLI_gset_remove(f_node->bm_other_verts, v, NULL);
- }
- }
- } while ((l_iter = l_iter->next) != l_first);
+ } 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 */
- BM_log_face_removed(pbvh->bm_log, f);
+ if (log_face) {
+ BM_log_face_removed(pbvh->bm_log, f);
+ }
/* mark node for update */
- f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals;
+ f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals | PBVH_UpdateTris;
+}
+
+void BKE_pbvh_bmesh_remove_face(PBVH *pbvh, BMFace *f, bool log_face)
+{
+ pbvh_bmesh_face_remove(pbvh, f, log_face, true);
+}
+
+void BKE_pbvh_bmesh_remove_vertex(PBVH *pbvh, BMVert *v, bool log_vert)
+{
+ pbvh_bmesh_vert_remove(pbvh, v);
+
+ if (log_vert) {
+ BM_log_vert_removed(pbvh->bm_log, v, pbvh->cd_vert_mask_offset);
+ }
+}
+
+static bool point_in_node(const PBVHNode *node, const float co[3])
+{
+ return co[0] >= node->vb.bmin[0] && co[0] <= node->vb.bmax[0] && co[1] >= node->vb.bmin[1] &&
+ co[1] <= node->vb.bmax[1] && co[2] >= node->vb.bmin[2] && co[2] <= node->vb.bmax[2];
+}
+
+static void bke_pbvh_insert_face_finalize(PBVH *pbvh, BMFace *f, const int ni)
+{
+ PBVHNode *node = pbvh->nodes + ni;
+ BM_ELEM_CD_SET_INT(f, pbvh->cd_face_node_offset, ni);
+
+ BLI_table_gset_add(node->bm_faces, f);
+
+ int updateflag = PBVH_UpdateTris | PBVH_UpdateBB | PBVH_UpdateDrawBuffers |
+ PBVH_UpdateCurvatureDir;
+ updateflag |= PBVH_UpdateColor | PBVH_UpdateMask | PBVH_UpdateNormals | PBVH_UpdateOriginalBB;
+ updateflag |= PBVH_UpdateVisibility | PBVH_UpdateRedraw;
+
+ node->flag |= updateflag;
+
+ // ensure verts are in pbvh
+ BMLoop *l = f->l_first;
+ do {
+ const int ni2 = BM_ELEM_CD_GET_INT(l->v, pbvh->cd_vert_node_offset);
+ MDynTopoVert *mv = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, l->v);
+
+ BB_expand(&node->vb, l->v->co);
+ BB_expand(&node->orig_vb, mv->origco);
+
+ if (ni2 == DYNTOPO_NODE_NONE) {
+ BM_ELEM_CD_SET_INT(l->v, pbvh->cd_vert_node_offset, ni);
+ BLI_table_gset_add(node->bm_unique_verts, l->v);
+ }
+ else {
+ PBVHNode *node2 = pbvh->nodes + ni2;
+
+ BLI_table_gset_add(node->bm_other_verts, l->v);
+
+ node2->flag |= updateflag;
+
+ BB_expand(&node2->vb, l->v->co);
+ BB_expand(&node2->orig_vb, mv->origco);
+ }
+ l = l->next;
+ } while (l != f->l_first);
+}
+
+static void bke_pbvh_insert_face(PBVH *pbvh, struct BMFace *f)
+{
+ int i = 0;
+ bool ok = false;
+ int ni = -1;
+
+#if 1
+ while (i < pbvh->totnode) {
+ PBVHNode *node = pbvh->nodes + i;
+ bool ok2 = false;
+
+ if (node->flag & PBVH_Leaf) {
+ ok = true;
+ ni = i;
+ break;
+ }
+
+ if (node->children_offset == 0) {
+ continue;
+ }
+
+ for (int j = 0; j < 2; j++) {
+ int ni2 = node->children_offset + j;
+ if (ni2 == 0) {
+ continue;
+ }
+
+ PBVHNode *node2 = pbvh->nodes + ni2;
+ BMLoop *l = f->l_first;
+
+ do {
+ if (point_in_node(node2, l->v->co)) {
+ i = ni2;
+ ok2 = true;
+ break;
+ }
+
+ l = l->next;
+ } while (l != f->l_first);
+
+ if (ok2) {
+ break;
+ }
+ }
+
+ if (!ok2) {
+ break;
+ }
+ }
+#endif
+
+ if (!ok) {
+ // find closest node
+ float co[3];
+ int tot = 0;
+ BMLoop *l = f->l_first;
+
+ zero_v3(co);
+
+ do {
+ add_v3_v3(co, l->v->co);
+ l = l->next;
+ tot++;
+ } while (l != f->l_first);
+
+ mul_v3_fl(co, 1.0f / (float)tot);
+ float mindis = 1e17;
+
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *node = pbvh->nodes + i;
+
+ if (!(node->flag & PBVH_Leaf)) {
+ continue;
+ }
+
+ float cent[3];
+ add_v3_v3v3(cent, node->vb.bmin, node->vb.bmax);
+ mul_v3_fl(cent, 0.5f);
+
+ float dis = len_squared_v3v3(co, cent);
+ if (dis < mindis) {
+ mindis = dis;
+ ni = i;
+ }
+ }
+ }
+
+ if (ni < 0) {
+ fprintf(stderr, "pbvh error!\n");
+ fflush(stderr);
+ return;
+ }
+
+ bke_pbvh_insert_face_finalize(pbvh, f, ni);
+}
+
+void BKE_pbvh_bmesh_add_face(PBVH *pbvh, struct BMFace *f, bool log_face, bool force_tree_walk)
+{
+ int ni = -1;
+
+ // look for node in surrounding geometry
+ BMLoop *l = f->l_first;
+ do {
+ ni = BM_ELEM_CD_GET_INT(l->radial_next->f, pbvh->cd_face_node_offset);
+
+ if (ni >= 0 && (!(pbvh->nodes[ni].flag & PBVH_Leaf) || ni >= pbvh->totnode)) {
+ printf("EEK! ni: %d totnode: %d\n", ni, pbvh->totnode);
+ l = l->next;
+ continue;
+ }
+
+ if (ni >= 0 && (pbvh->nodes[ni].flag & PBVH_Leaf)) {
+ break;
+ }
+
+ l = l->next;
+ } while (l != f->l_first);
+
+ if (ni < 0 || force_tree_walk) {
+ bke_pbvh_insert_face(pbvh, f);
+ }
+ else {
+ BM_ELEM_CD_SET_INT(f, pbvh->cd_face_node_offset, ni);
+ bke_pbvh_insert_face_finalize(pbvh, f, ni);
+ }
+
+ if (log_face) {
+ BM_log_face_added(pbvh->bm_log, f);
+ }
}
static void pbvh_bmesh_edge_loops(BLI_Buffer *buf, BMEdge *e)
@@ -711,25 +1360,16 @@ static void pbvh_bmesh_edge_loops(BLI_Buffer *buf, BMEdge *e)
}
}
-static void pbvh_bmesh_node_drop_orig(PBVHNode *node)
-{
- if (node->bm_orco) {
- MEM_freeN(node->bm_orco);
- }
- if (node->bm_ortri) {
- MEM_freeN(node->bm_ortri);
- }
- node->bm_orco = NULL;
- node->bm_ortri = NULL;
- node->bm_tot_ortri = 0;
-}
-
/****************************** EdgeQueue *****************************/
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 +1379,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
@@ -750,11 +1391,74 @@ typedef struct {
EdgeQueue *q;
BLI_mempool *pool;
BMesh *bm;
+ DyntopoMaskCB mask_cb;
+ void *mask_cb_data;
+ int cd_dyn_vert;
int cd_vert_mask_offset;
int cd_vert_node_offset;
int cd_face_node_offset;
+ float avg_elen;
+ float max_elen;
+ float min_elen;
+ float totedge;
} EdgeQueueContext;
+BLI_INLINE float maskcb_get(EdgeQueueContext *eq_ctx, BMEdge *e)
+{
+ if (eq_ctx->mask_cb) {
+ SculptVertRef sv1 = {(intptr_t)e->v1};
+ SculptVertRef sv2 = {(intptr_t)e->v2};
+
+ float w1 = eq_ctx->mask_cb(sv1, eq_ctx->mask_cb_data);
+ float w2 = eq_ctx->mask_cb(sv2, eq_ctx->mask_cb_data);
+
+ return (w1 + w2) * 0.5f;
+ }
+
+ return 1.0f;
+}
+
+BLI_INLINE float calc_weighted_edge_split(EdgeQueueContext *eq_ctx, BMVert *v1, BMVert *v2)
+{
+#ifdef FANCY_EDGE_WEIGHTS
+ float l = len_squared_v3v3(v1->co, v2->co);
+ float val = (float)BM_vert_edge_count(v1) + (float)BM_vert_edge_count(v2);
+ val = MAX2(val * 0.5 - 6.0f, 1.0f);
+ val = powf(val, 0.5);
+ l *= val;
+
+ return l;
+#elif 0 // 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)
+{
+#ifdef FANCY_EDGE_WEIGHTS
+ float l = len_squared_v3v3(v1->co, v2->co);
+ float val = (float)BM_vert_edge_count(v1) + (float)BM_vert_edge_count(v2);
+ val = MAX2(val * 0.5 - 6.0f, 1.0f);
+ val = powf(val, 0.5);
+ l /= val;
+
+ // 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 +1498,57 @@ static void pbvh_bmesh_edge_tag_verify(PBVH *pbvh)
}
#endif
-static bool edge_queue_tri_in_sphere(const EdgeQueue *q, BMFace *f)
+static bool edge_queue_vert_in_sphere(const EdgeQueue *q, BMVert *v)
{
- BMVert *v_tri[3];
- float c[3];
+ /* Check if triangle intersects the sphere */
+ return len_squared_v3v3(q->center, v->co) <= q->radius_squared;
+}
- /* Get closest point in triangle to sphere center */
- BM_face_as_array_vert_tri(f, v_tri);
+/*
+ Profiling revealed the accurate distance to tri in blenlib was too slow,
+ so we use a simpler version here
+ */
+static float dist_to_tri_sphere_simple(
+ float p[3], float v1[3], float v2[3], float v3[3], float n[3])
+{
+ float co[3];
+
+ float dis = len_squared_v3v3(p, v1);
+ dis = fmin(dis, len_squared_v3v3(p, v2));
+ dis = fmin(dis, len_squared_v3v3(p, v3));
+
+ add_v3_v3v3(co, v1, v2);
+ mul_v3_fl(co, 0.5f);
+ dis = fmin(dis, len_squared_v3v3(p, co));
+
+ add_v3_v3v3(co, v2, v3);
+ mul_v3_fl(co, 0.5f);
+ dis = fmin(dis, len_squared_v3v3(p, co));
+
+ add_v3_v3v3(co, v3, v1);
+ mul_v3_fl(co, 0.5f);
+ dis = fmin(dis, len_squared_v3v3(p, co));
- closest_on_tri_to_point_v3(c, q->center, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co);
+ add_v3_v3v3(co, v1, v2);
+ add_v3_v3(co, v3);
+ mul_v3_fl(co, 1.0f / 3.0f);
+ dis = fmin(dis, len_squared_v3v3(p, co));
+
+ return dis;
+}
+
+static bool edge_queue_tri_in_sphere(const EdgeQueue *q, BMFace *f)
+{
+ BMLoop *l = f->l_first;
/* Check if triangle intersects the sphere */
- return len_squared_v3v3(q->center, c) <= q->radius_squared;
+ float dis = dist_to_tri_sphere_simple((float *)q->center,
+ (float *)l->v->co,
+ (float *)l->next->v->co,
+ (float *)l->prev->v->co,
+ (float *)f->no);
+
+ return dis <= q->radius_squared;
}
static bool edge_queue_tri_in_circle(const EdgeQueue *q, BMFace *f)
@@ -827,28 +1570,67 @@ static bool edge_queue_tri_in_circle(const EdgeQueue *q, BMFace *f)
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)
+typedef struct EdgeQueueThreadData {
+ PBVH *pbvh;
+ PBVHNode *node;
+ BMEdge **edges;
+ EdgeQueueContext *eq_ctx;
+ int totedge;
+ int size;
+} EdgeQueueThreadData;
+
+static 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)
{
- return BM_ELEM_CD_GET_FLOAT(v, eq_ctx->cd_vert_mask_offset) < 1.0f;
+ 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;
}
static void edge_queue_insert(EdgeQueueContext *eq_ctx, BMEdge *e, float priority)
{
- /* 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
- * should already make the brush move the vertices only 50%, which means
- * that topology updates will also happen less frequent, that should be
- * enough. */
- if (((eq_ctx->cd_vert_mask_offset == -1) ||
- (check_mask(eq_ctx, e->v1) || check_mask(eq_ctx, e->v2))) &&
- !(BM_elem_flag_test_bool(e->v1, BM_ELEM_HIDDEN) ||
- BM_elem_flag_test_bool(e->v2, BM_ELEM_HIDDEN))) {
+ void **elems = eq_ctx->q->elems;
+ BLI_array_declare(elems);
+ BLI_array_len_set(elems, eq_ctx->q->totelems);
+
+ if (eq_ctx->cd_vert_mask_offset == -1 ||
+ !((e->v1->head.hflag | e->v2->head.hflag) & BM_ELEM_HIDDEN)) {
+ float dis = len_v3v3(e->v1->co, e->v2->co);
+ eq_ctx->avg_elen += dis;
+ eq_ctx->max_elen = MAX2(eq_ctx->max_elen, dis);
+ eq_ctx->min_elen = MIN2(eq_ctx->min_elen, dis);
+ eq_ctx->totedge += 1.0f;
+
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);
@@ -862,7 +1644,9 @@ static void long_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 w = maskcb_get(eq_ctx, e);
+ const float len_sq = BM_edge_calc_length_squared(e) * w * w;
+
if (len_sq > eq_ctx->q->limit_len_squared) {
edge_queue_insert(eq_ctx, e, -len_sq);
}
@@ -870,13 +1654,17 @@ static void long_edge_queue_edge_add(EdgeQueueContext *eq_ctx, BMEdge *e)
}
#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
-static void long_edge_queue_edge_add_recursive(
- EdgeQueueContext *eq_ctx, BMLoop *l_edge, BMLoop *l_end, const float len_sq, float limit_len)
+static void long_edge_queue_edge_add_recursive(EdgeQueueContext *eq_ctx,
+ BMLoop *l_edge,
+ BMLoop *l_end,
+ const float len_sq,
+ float limit_len,
+ int depth)
{
BLI_assert(len_sq > square_f(limit_len));
# ifdef USE_EDGEQUEUE_FRONTFACE
- if (eq_ctx->q->use_view_normal) {
+ if (depth > DEPTH_START_LIMIT && eq_ctx->q->use_view_normal) {
if (dot_v3v3(l_edge->f->no, eq_ctx->q->view_normal) < 0.0f) {
return;
}
@@ -896,13 +1684,6 @@ static void long_edge_queue_edge_add_recursive(
}
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;
@@ -911,18 +1692,23 @@ static void long_edge_queue_edge_add_recursive(
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++) {
+ for (int i = 0; i < (int)ARRAY_SIZE(l_adjacent); i++) {
float len_sq_other = BM_edge_calc_length_squared(l_adjacent[i]->e);
+ float w = maskcb_get(eq_ctx, l_adjacent[i]->e);
+
+ len_sq_other *= w * w;
+
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(
- eq_ctx, l_adjacent[i]->radial_next, l_adjacent[i], len_sq_other, limit_len);
+ long_edge_queue_edge_add_recursive(eq_ctx,
+ l_adjacent[i]->radial_next,
+ l_adjacent[i],
+ len_sq_other,
+ limit_len,
+ depth + 1);
}
}
} while ((l_iter = l_iter->radial_next) != l_end);
-
-# undef EVEN_EDGELEN_THRESHOLD
-# undef EVEN_GENERATION_SCALE
}
}
#endif /* USE_EDGEQUEUE_EVEN_SUBDIV */
@@ -933,17 +1719,17 @@ 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);
}
}
}
-static void long_edge_queue_face_add(EdgeQueueContext *eq_ctx, BMFace *f)
+static void long_edge_queue_face_add(EdgeQueueContext *eq_ctx, BMFace *f, bool ignore_frontface)
{
#ifdef USE_EDGEQUEUE_FRONTFACE
- if (eq_ctx->q->use_view_normal) {
+ if (!ignore_frontface && eq_ctx->q->use_view_normal) {
if (dot_v3v3(f->no, eq_ctx->q->view_normal) < 0.0f) {
return;
}
@@ -956,10 +1742,19 @@ static void long_edge_queue_face_add(EdgeQueueContext *eq_ctx, BMFace *f)
BMLoop *l_iter = l_first;
do {
#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
- const float len_sq = BM_edge_calc_length_squared(l_iter->e);
+ float len_sq = BM_edge_calc_length_squared(l_iter->e);
+ float w = maskcb_get(eq_ctx, l_iter->e);
+
+ len_sq *= w * w;
+
if (len_sq > eq_ctx->q->limit_len_squared) {
- long_edge_queue_edge_add_recursive(
- eq_ctx, l_iter->radial_next, l_iter, len_sq, eq_ctx->q->limit_len);
+ long_edge_queue_edge_add_recursive(eq_ctx,
+ l_iter->radial_next,
+ l_iter,
+ len_sq,
+ eq_ctx->q->limit_len,
+ DEPTH_START_LIMIT +
+ 1); // ignore_frontface ? 0 : DEPTH_START_LIMIT+1);
}
#else
long_edge_queue_edge_add(eq_ctx, l_iter->e);
@@ -990,6 +1785,242 @@ static void short_edge_queue_face_add(EdgeQueueContext *eq_ctx, BMFace *f)
}
}
+static void short_edge_queue_edge_add_recursive_2(EdgeQueueThreadData *tdata,
+ BMLoop *l_edge,
+ BMLoop *l_end,
+ const float len_sq,
+ float limit_len,
+ int depth)
+{
+ BLI_assert(len_sq > square_f(limit_len));
+
+ if (l_edge->e->head.hflag & BM_ELEM_TAG) {
+ return;
+ }
+
+#ifdef USE_EDGEQUEUE_FRONTFACE
+ if (depth > DEPTH_START_LIMIT && 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)) {
+ 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 < (int)ARRAY_SIZE(l_adjacent); i++) {
+
+ float len_sq_other = calc_weighted_edge_collapse(
+ 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);
+ short_edge_queue_edge_add_recursive_2(tdata,
+ l_adjacent[i]->radial_next,
+ l_adjacent[i],
+ len_sq_other,
+ limit_len,
+ depth + 1);
+ }
+ }
+ } while ((l_iter = l_iter->radial_next) != l_end);
+ }
+}
+
+static void long_edge_queue_edge_add_recursive_2(EdgeQueueThreadData *tdata,
+ BMLoop *l_edge,
+ BMLoop *l_end,
+ const float len_sq,
+ float limit_len,
+ int depth)
+{
+ BLI_assert(len_sq > square_f(limit_len));
+
+ if (l_edge->e->head.hflag & BM_ELEM_TAG) {
+ return;
+ }
+
+#ifdef USE_EDGEQUEUE_FRONTFACE
+ if (depth > DEPTH_START_LIMIT && 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)) {
+ 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 < (int)ARRAY_SIZE(l_adjacent); i++) {
+ BMEdge *e = l_adjacent[i]->e;
+
+ float len_sq_other = calc_weighted_edge_split(
+ tdata->eq_ctx, l_adjacent[i]->e->v1, l_adjacent[i]->e->v2);
+
+ float w = maskcb_get(tdata->eq_ctx, e);
+
+ len_sq_other *= w * w;
+
+ if (len_sq_other > max_ff(len_sq_cmp, limit_len_sq)) {
+ long_edge_queue_edge_add_recursive_2(tdata,
+ l_adjacent[i]->radial_next,
+ l_adjacent[i],
+ len_sq_other,
+ limit_len,
+ depth + 1);
+ }
+ }
+ } while ((l_iter = l_iter->radial_next) != l_end);
+ }
+}
+
+static 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 {
+ // try to improve convergence by applying a small amount of smoothing to topology,
+ // but tangentially to surface.
+ surface_smooth_v_safe(l_iter->v);
+
+#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
+ float w = maskcb_get(eq_ctx, l_iter->e);
+ float len_sq = BM_edge_calc_length_squared(l_iter->e);
+
+ len_sq *= w * w;
+
+ 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, 0);
+ }
+#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
+}
+
+static 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 {
+ float w = maskcb_get(eq_ctx, l_iter->e);
+
+ if (w == 0.0f) {
+ continue;
+ }
+
+#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
+ float len_sq = calc_weighted_edge_collapse(eq_ctx, l_iter->e->v1, l_iter->e->v2);
+ len_sq /= w * w;
+
+ if (len_sq < eq_ctx->q->limit_len_squared) {
+ short_edge_queue_edge_add_recursive_2(
+ tdata, l_iter->radial_next, l_iter, len_sq, eq_ctx->q->limit_len, 0);
+ }
+#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 +2039,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 +2058,75 @@ 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;
+
+ float w = -calc_weighted_edge_split(eq_ctx, e->v1, e->v2);
+ float w2 = maskcb_get(eq_ctx, e);
+
+ w *= w2 * w2;
+
+ edge_queue_insert(eq_ctx, e, w);
+ }
+
+ if (td->edges) {
+ MEM_freeN(td->edges);
}
}
+ BLI_array_free(tdata);
}
/* Create a priority queue containing vertex pairs connected by a
@@ -1071,6 +2147,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 +2166,77 @@ 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];
+ float w = calc_weighted_edge_collapse(eq_ctx, e->v1, e->v2);
+ float w2 = maskcb_get(eq_ctx, e);
+
+ if (w2 > 0.0f) {
+ w /= w2 * w2;
+ }
+ else {
+ w = 100000.0f;
+ }
+
+ e->head.hflag &= ~BM_ELEM_TAG;
+ edge_queue_insert(eq_ctx, e, w);
+ }
+
+ if (td->edges) {
+ MEM_freeN(td->edges);
}
}
+
+ BLI_array_free(tdata);
}
/*************************** Topology update **************************/
@@ -1119,7 +2246,13 @@ 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];
+ MDynTopoVert *mv1 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, e->v1);
+ MDynTopoVert *mv2 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, e->v2);
+
+ bool boundary = (mv1->flag & DYNVERT_BOUNDARY) && (mv2->flag & DYNVERT_BOUNDARY);
/* Get all faces adjacent to the edge */
pbvh_bmesh_edge_loops(edge_loops, e);
@@ -1131,19 +2264,32 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
int node_index = BM_ELEM_CD_GET_INT(e->v1, eq_ctx->cd_vert_node_offset);
BMVert *v_new = pbvh_bmesh_vert_create(
- pbvh, node_index, co_mid, no_mid, eq_ctx->cd_vert_mask_offset);
+ pbvh, node_index, co_mid, no_mid, NULL, eq_ctx->cd_vert_mask_offset);
+ // 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;
- /* 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);
- float mask_v2 = BM_ELEM_CD_GET_FLOAT(e->v2, eq_ctx->cd_vert_mask_offset);
- float mask_v_new = 0.5f * (mask_v1 + mask_v2);
+ e1->head.hflag = e2->head.hflag = eflag;
+ v_new->head.hflag = vflag;
- BM_ELEM_CD_SET_FLOAT(v_new, eq_ctx->cd_vert_mask_offset, mask_v_new);
+ /*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, (const void **)vsrcs, (float *)vws, NULL, 2, v_new->head.data);
+
+ if (boundary) {
+ MDynTopoVert *mv_new = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v_new);
+ mv_new->flag |= DYNVERT_BOUNDARY;
}
/* For each face, add two new triangles and delete the original */
- for (int i = 0; i < edge_loops->count; i++) {
+ for (int i = 0; i < (int)edge_loops->count; i++) {
BMLoop *l_adj = BLI_buffer_at(edge_loops, BMLoop *, i);
BMFace *f_adj = l_adj->f;
BMFace *f_new;
@@ -1198,8 +2344,43 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
v_tri[1] = v_new;
v_tri[2] = v_opp;
bm_edges_from_tri(pbvh->bm, v_tri, e_tri);
- f_new = pbvh_bmesh_face_create(pbvh, ni, v_tri, e_tri, f_adj);
- long_edge_queue_face_add(eq_ctx, f_new);
+ f_new = pbvh_bmesh_face_create(pbvh, ni, v_tri, e_tri, f_adj, false, true);
+ long_edge_queue_face_add(eq_ctx, f_new, true);
+
+ pbvh_bmesh_copy_facedata(bm, f_new, f_adj);
+
+ // customdata interpolation
+ 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, (const void **)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, (const void **)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, (const void **)lsrcs, lws, lws, 1, f_new->l_first->prev->head.data);
v_tri[0] = v_new;
v_tri[1] = v2;
@@ -1207,25 +2388,40 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
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);
+
+ f_new = pbvh_bmesh_face_create(pbvh, ni, v_tri, e_tri, f_adj, false, true);
+ long_edge_queue_face_add(eq_ctx, f_new, true);
+
+ pbvh_bmesh_copy_facedata(bm, f_new, f_adj);
+
+ // customdata interpolation
+ lsrcs[0] = lfirst->head.data;
+ lsrcs[1] = lfirst->next->head.data;
+ lws[0] = lws[1] = 0.5f;
+
+ CustomData_bmesh_interp(
+ &pbvh->bm->ldata, (const void **)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, (const void **)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, (const void **)lsrcs, lws, lws, 1, f_new->l_first->prev->head.data);
/* Delete original */
- pbvh_bmesh_face_remove(pbvh, f_adj);
+ pbvh_bmesh_face_remove(pbvh, f_adj, true, true);
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);
}
}
@@ -1234,12 +2430,39 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx,
PBVH *pbvh,
- BLI_Buffer *edge_loops)
+ BLI_Buffer *edge_loops,
+ int max_steps)
{
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++ > max_steps) {
+ 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;
@@ -1250,6 +2473,7 @@ static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx,
if (!(e = BM_edge_exists(v1, v2))) {
continue;
}
+
#ifdef USE_EDGEQUEUE_TAG
EDGE_QUEUE_DISABLE(e);
#endif
@@ -1261,7 +2485,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 +2502,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,9 +2534,29 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
{
BMVert *v_del, *v_conn;
+ // customdata interpolation
+ 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;
+ }
+ }
+ }
+
/* 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)) {
+ if (DYNTOPO_MASK(eq_ctx->cd_vert_mask_offset, v1) <
+ DYNTOPO_MASK(eq_ctx->cd_vert_mask_offset, v2)) {
v_del = v1;
v_conn = v2;
}
@@ -1314,7 +2573,28 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
while ((l_adj = e->l)) {
BMFace *f_adj = l_adj->f;
- pbvh_bmesh_face_remove(pbvh, f_adj);
+ 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);
+
+ pbvh_bmesh_face_remove(pbvh, f_adj, true, true);
BM_face_kill(pbvh->bm, f_adj);
}
@@ -1329,7 +2609,66 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
* really buy anything. */
BLI_buffer_clear(deleted_faces);
- BMLoop *l;
+ BMLoop *l = NULL;
+ BMLoop **ls = NULL;
+ void **blocks = NULL;
+ float *ws = NULL;
+
+ BLI_array_staticdeclare(ls, 64);
+ BLI_array_staticdeclare(blocks, 64);
+ BLI_array_staticdeclare(ws, 64);
+
+ int totl = 0;
+
+ BM_LOOPS_OF_VERT_ITER_BEGIN (l, v_del) {
+ BLI_array_append(ls, l);
+ totl++;
+ }
+ BM_LOOPS_OF_VERT_ITER_END;
+
+ BM_LOOPS_OF_VERT_ITER_BEGIN (l, v_conn) {
+ BLI_array_append(ls, l);
+ totl++;
+ }
+ BM_LOOPS_OF_VERT_ITER_END;
+
+ float w = totl > 0 ? 1.0f / (float)(totl) : 1.0f;
+
+ for (int i = 0; i < totl; i++) {
+ BLI_array_append(blocks, ls[i]->head.data);
+ BLI_array_append(ws, w);
+ }
+
+ // snap customdata
+ if (totl > 0) {
+ CustomData_bmesh_interp(
+ &pbvh->bm->ldata, (const void **)blocks, ws, NULL, totl, ls[0]->head.data);
+ //*
+ BM_LOOPS_OF_VERT_ITER_BEGIN (l, v_del) {
+ BMLoop *l2 = l->v != v_del ? l->next : l;
+
+ if (l2 == ls[0]) {
+ continue;
+ }
+
+ CustomData_bmesh_copy_data(
+ &pbvh->bm->ldata, &pbvh->bm->ldata, ls[0]->head.data, &l2->head.data);
+ }
+ BM_LOOPS_OF_VERT_ITER_END;
+
+ BM_LOOPS_OF_VERT_ITER_BEGIN (l, v_conn) {
+ BMLoop *l2 = l->v != v_conn ? l->next : l;
+
+ if (l2 == ls[0]) {
+ continue;
+ }
+
+ CustomData_bmesh_copy_data(
+ &pbvh->bm->ldata, &pbvh->bm->ldata, ls[0]->head.data, &l2->head.data);
+ }
+ BM_LOOPS_OF_VERT_ITER_END;
+ //*/
+ }
BM_LOOPS_OF_VERT_ITER_BEGIN (l, v_del) {
BMFace *existing_face;
@@ -1337,15 +2676,6 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
/* Get vertices, replace use of v_del with v_conn */
// BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v_tri, 3);
BMFace *f = l->f;
-#if 0
- BMVert *v_tri[3];
- BM_face_as_array_vert_tri(f, v_tri);
- for (int i = 0; i < 3; i++) {
- if (v_tri[i] == v_del) {
- v_tri[i] = v_conn;
- }
- }
-#endif
/* Check if a face using these vertices already exists. If so,
* skip adding this face and mark the existing one for
@@ -1357,7 +2687,19 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
if (UNLIKELY(existing_face = bm_face_exists_tri_from_loop_vert(l->next, v_conn)))
#endif
{
- BLI_buffer_append(deleted_faces, BMFace *, existing_face);
+ bool ok = true;
+
+ // check we're not already in deleted_faces
+ for (int i = 0; i < (int)deleted_faces->count; i++) {
+ if (BLI_buffer_at(deleted_faces, BMFace *, i) == existing_face) {
+ ok = false;
+ break;
+ }
+ }
+
+ if (ok) {
+ BLI_buffer_append(deleted_faces, BMFace *, existing_face);
+ }
}
else
{
@@ -1368,11 +2710,25 @@ 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, false, true);
+
+ 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);
/* 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);
}
}
@@ -1381,7 +2737,7 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
BM_LOOPS_OF_VERT_ITER_END;
/* Delete the tagged faces */
- for (int i = 0; i < deleted_faces->count; i++) {
+ for (int i = 0; i < (int)deleted_faces->count; i++) {
BMFace *f_del = BLI_buffer_at(deleted_faces, BMFace *, i);
/* Get vertices and edges of face */
@@ -1398,8 +2754,21 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
v_tri[2] = l_iter->v;
e_tri[2] = l_iter->e;
+ BMLoop *l1 = f_del->l_first;
+ do {
+ if (!l1->e) {
+ printf("bmesh error!\n");
+ l1->e = BM_edge_exists(l1->v, l1->next->v);
+ if (!l1->e) {
+ // create
+ l1->e = BM_edge_create(pbvh->bm, l1->v, l1->next->v, NULL, 0);
+ }
+ }
+ l1 = l1->next;
+ } while (l1 != f_del->l_first);
+
/* Remove the face */
- pbvh_bmesh_face_remove(pbvh, f_del);
+ pbvh_bmesh_face_remove(pbvh, f_del, true, true);
BM_face_kill(pbvh->bm, f_del);
/* Check if any of the face's edges are now unused by any
@@ -1430,7 +2799,10 @@ 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, false);
+
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);
@@ -1439,9 +2811,15 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
* note that we can often get-away without this but causes T48779 */
BM_LOOPS_OF_VERT_ITER_BEGIN (l, v_conn) {
PBVHNode *f_node = pbvh_bmesh_node_from_face(pbvh, l->f);
- f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals | PBVH_UpdateBB;
+ f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals | PBVH_UpdateBB |
+ PBVH_UpdateTris;
}
BM_LOOPS_OF_VERT_ITER_END;
+
+ if (BM_vert_is_boundary(v_conn)) {
+ MDynTopoVert *mv_conn = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v_conn);
+ mv_conn->flag |= DYNVERT_BOUNDARY;
+ }
}
/* Delete v_del */
@@ -1450,19 +2828,152 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
/* v_conn == NULL is OK */
BLI_ghash_insert(deleted_verts, v_del, v_conn);
BM_vert_kill(pbvh->bm, v_del);
+
+ BLI_array_free(ws);
+ BLI_array_free(blocks);
+ BLI_array_free(ls);
+}
+
+static void pbvh_bmesh_regen_node_verts(PBVH *pbvh, PBVHNode *node)
+{
+ int usize = BLI_table_gset_len(node->bm_other_verts);
+ int osize = BLI_table_gset_len(node->bm_other_verts);
+
+ BLI_table_gset_free(node->bm_other_verts, NULL);
+ BLI_table_gset_free(node->bm_unique_verts, NULL);
+
+ node->bm_unique_verts = BLI_table_gset_new("bm_unique_verts");
+ node->bm_other_verts = BLI_table_gset_new("bm_other_verts");
+
+ const int cd_vert_node = pbvh->cd_vert_node_offset;
+ const int ni = (int)(node - pbvh->nodes);
+
+ BMFace *f;
+ TGSET_ITER (f, node->bm_faces) {
+ BMLoop *l = f->l_first;
+ do {
+ int ni2 = BM_ELEM_CD_GET_INT(l->v, cd_vert_node);
+ if (ni2 == ni) {
+ BLI_table_gset_add(node->bm_unique_verts, l->v);
+ }
+ else {
+ BLI_table_gset_add(node->bm_other_verts, l->v);
+ }
+ } while ((l = l->next) != f->l_first);
+ }
+ TGSET_ITER_END;
+
+ if (usize != BLI_table_gset_len(node->bm_unique_verts)) {
+ printf("possible pbvh error: bm_unique_verts might have had bad data. old: %d, new: %d\n",
+ usize,
+ BLI_table_gset_len(node->bm_unique_verts));
+ }
+
+ if (osize != BLI_table_gset_len(node->bm_other_verts)) {
+ printf("possible pbvh error: bm_other_verts might have had bad data. old: %d, new: %d\n",
+ osize,
+ BLI_table_gset_len(node->bm_other_verts));
+ }
+}
+
+void BKE_pbvh_bmesh_mark_node_regen(PBVH *pbvh, PBVHNode *node)
+{
+ node->flag |= PBVH_RebuildNodeVerts;
+}
+
+void BKE_pbvh_bmesh_regen_node_verts(PBVH *pbvh)
+{
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *node = pbvh->nodes + i;
+
+ if (!(node->flag & PBVH_Leaf) || !(node->flag & PBVH_RebuildNodeVerts)) {
+ continue;
+ }
+
+ pbvh_bmesh_regen_node_verts(pbvh, node);
+ }
+}
+
+void BKE_pbvh_bmesh_update_origvert(
+ PBVH *pbvh, BMVert *v, float **r_co, float **r_no, float **r_color, bool log_undo)
+{
+ MDynTopoVert *mv = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v);
+
+ if (log_undo) {
+ BM_log_vert_before_modified(pbvh->bm_log, v, pbvh->cd_vert_mask_offset, r_color != NULL);
+ }
+
+ if (r_co || r_no) {
+
+ copy_v3_v3(mv->origco, v->co);
+ copy_v3_v3(mv->origno, v->no);
+
+ if (r_co) {
+ *r_co = mv->origco;
+ }
+
+ if (r_no) {
+ *r_no = mv->origno;
+ }
+ }
+
+ if (r_color && pbvh->cd_vcol_offset >= 0) {
+ MPropCol *ml1 = BM_ELEM_CD_GET_VOID_P(v, pbvh->cd_vcol_offset);
+
+ copy_v4_v4(mv->origcolor, ml1->color);
+
+ if (r_color) {
+ *r_color = mv->origcolor;
+ }
+ }
+ else if (r_color) {
+ *r_color = NULL;
+ }
}
static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx,
PBVH *pbvh,
- BLI_Buffer *deleted_faces)
+ BLI_Buffer *deleted_faces,
+ int max_steps)
{
const float min_len_squared = pbvh->bm_min_edge_len * pbvh->bm_min_edge_len;
bool any_collapsed = false;
/* 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((unsigned int)(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++ > max_steps) {
+ 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 +2993,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 +3009,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;
@@ -1507,173 +3042,312 @@ static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx,
/************************* Called from pbvh.c *************************/
-bool pbvh_bmesh_node_raycast(PBVHNode *node,
+bool BKE_pbvh_bmesh_check_origdata(PBVH *pbvh, BMVert *v, int stroke_id)
+{
+ MDynTopoVert *mv = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v);
+
+ if (mv->stroke_id != stroke_id) {
+ float *dummy;
+
+ BKE_pbvh_bmesh_update_origvert(pbvh, v, &dummy, &dummy, &dummy, false);
+ mv->stroke_id = stroke_id;
+ return true;
+ }
+
+ return false;
+}
+
+bool pbvh_bmesh_node_raycast(PBVH *pbvh,
+ PBVHNode *node,
const float ray_start[3],
const float ray_normal[3],
struct IsectRayPrecalc *isect_precalc,
float *depth,
bool use_original,
- int *r_active_vertex_index,
- float *r_face_normal)
+ SculptVertRef *r_active_vertex_index,
+ SculptFaceRef *r_active_face_index,
+ float *r_face_normal,
+ int stroke_id)
{
bool hit = false;
float nearest_vertex_co[3] = {0.0f};
+ float nearest_vertex_dist = 1e17;
+
+ BKE_pbvh_bmesh_check_tris(pbvh, node);
+
+ PBVHTriBuf *tribuf = node->tribuf;
+ const int cd_dyn_vert = pbvh->cd_dyn_vert;
- 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);
+ for (int i = 0; i < node->tribuf->tottri; i++) {
+ PBVHTri *tri = tribuf->tris + i;
+ BMVert *v1 = (BMVert *)tribuf->verts[tri->v[0]].i;
+ BMVert *v2 = (BMVert *)tribuf->verts[tri->v[1]].i;
+ BMVert *v3 = (BMVert *)tribuf->verts[tri->v[2]].i;
+
+ BMFace *f = (BMFace *)tri->f.i;
+
+ if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ continue;
}
- }
- else {
- GSetIterator gs_iter;
- GSET_ITER (gs_iter, node->bm_faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+ float *co1, *co2, *co3;
- BLI_assert(f->len == 3);
- if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
- BMVert *v_tri[3];
+ if (use_original) {
+ BKE_pbvh_bmesh_check_origdata(pbvh, v1, stroke_id);
+ BKE_pbvh_bmesh_check_origdata(pbvh, v2, stroke_id);
+ BKE_pbvh_bmesh_check_origdata(pbvh, v3, stroke_id);
+
+ co1 = BKE_PBVH_DYNVERT(cd_dyn_vert, v1)->origco;
+ co2 = BKE_PBVH_DYNVERT(cd_dyn_vert, v2)->origco;
+ co3 = BKE_PBVH_DYNVERT(cd_dyn_vert, v3)->origco;
+ }
+ else {
+ co1 = v1->co;
+ co2 = v2->co;
+ co3 = v3->co;
+ }
+ bool hit2 = ray_face_intersection_tri(ray_start, isect_precalc, co1, co2, co3, depth);
- BM_face_as_array_vert_tri(f, v_tri);
+ if (hit2) {
+ // ensure sculpt active vertex is set r_active_vertex_index
+
+ for (int j = 0; j < 3; j++) {
+ BMVert *v = (BMVert *)tribuf->verts[tri->v[j]].i;
+ float *co = BKE_PBVH_DYNVERT(cd_dyn_vert, v)->origco;
+
+ float dist = len_squared_v3v3(co, ray_start);
+ if (dist < nearest_vertex_dist) {
+ nearest_vertex_dist = dist;
+ copy_v3_v3(nearest_vertex_co, co);
- if (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_active_vertex_index) {
+ *r_active_vertex_index = tribuf->verts[tri->v[j]];
+ }
- if (r_face_normal) {
- normal_tri_v3(r_face_normal, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co);
+ if (r_active_face_index) {
+ *r_active_face_index = tri->f;
}
- 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)) {
- copy_v3_v3(nearest_vertex_co, v_tri[j]->co);
- *r_active_vertex_index = BM_elem_index_get(v_tri[j]);
- }
+ if (r_face_normal) {
+ float no[3];
+
+ if (use_original) {
+ copy_v3_v3(no, BKE_PBVH_DYNVERT(cd_dyn_vert, v1)->origno);
+ add_v3_v3(no, BKE_PBVH_DYNVERT(cd_dyn_vert, v2)->origno);
+ add_v3_v3(no, BKE_PBVH_DYNVERT(cd_dyn_vert, v3)->origno);
+ normalize_v3(no);
+ }
+ else {
+ copy_v3_v3(no, tri->no);
}
+
+ copy_v3_v3(r_face_normal, no);
}
}
}
+
+ hit = true;
}
}
return hit;
}
-bool BKE_pbvh_bmesh_node_raycast_detail(PBVHNode *node,
+bool BKE_pbvh_bmesh_node_raycast_detail(PBVH *pbvh,
+ PBVHNode *node,
const float ray_start[3],
struct IsectRayPrecalc *isect_precalc,
float *depth,
float *r_edge_length)
{
if (node->flag & PBVH_FullyHidden) {
- return 0;
+ return false;
}
- GSetIterator gs_iter;
- bool hit = false;
- BMFace *f_hit = NULL;
+ BKE_pbvh_bmesh_check_tris(pbvh, node);
+ for (int i = 0; i < node->tribuf->tottri; i++) {
+ PBVHTri *tri = node->tribuf->tris + i;
+ BMVert *v1 = (BMVert *)node->tribuf->verts[tri->v[0]].i;
+ BMVert *v2 = (BMVert *)node->tribuf->verts[tri->v[1]].i;
+ BMVert *v3 = (BMVert *)node->tribuf->verts[tri->v[2]].i;
+ BMFace *f = (BMFace *)tri->f.i;
- GSET_ITER (gs_iter, node->bm_faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+ if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ continue;
+ }
- BLI_assert(f->len == 3);
- if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
- BMVert *v_tri[3];
- bool hit_local;
- BM_face_as_array_vert_tri(f, v_tri);
- hit_local = ray_face_intersection_tri(
- ray_start, isect_precalc, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co, depth);
+ bool hit_local = ray_face_intersection_tri(
+ ray_start, isect_precalc, v1->co, v2->co, v3->co, depth);
- if (hit_local) {
- f_hit = f;
- hit = true;
- }
- }
- }
+ if (hit_local) {
+ float len1 = len_squared_v3v3(v1->co, v2->co);
+ float len2 = len_squared_v3v3(v2->co, v3->co);
+ float len3 = len_squared_v3v3(v3->co, v1->co);
- if (hit) {
- BMVert *v_tri[3];
- BM_face_as_array_vert_tri(f_hit, v_tri);
- float len1 = len_squared_v3v3(v_tri[0]->co, v_tri[1]->co);
- float len2 = len_squared_v3v3(v_tri[1]->co, v_tri[2]->co);
- float len3 = len_squared_v3v3(v_tri[2]->co, v_tri[0]->co);
+ /* detail returned will be set to the maximum allowed size, so take max here */
+ *r_edge_length = sqrtf(max_fff(len1, len2, len3));
- /* detail returned will be set to the maximum allowed size, so take max here */
- *r_edge_length = sqrtf(max_fff(len1, len2, len3));
+ return true;
+ }
}
- return hit;
+ return false;
}
-bool pbvh_bmesh_node_nearest_to_ray(PBVHNode *node,
+bool pbvh_bmesh_node_nearest_to_ray(PBVH *pbvh,
+ PBVHNode *node,
const float ray_start[3],
const float ray_normal[3],
float *depth,
float *dist_sq,
- bool use_original)
+ bool use_original,
+ int stroke_id)
{
bool hit = false;
- 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_nearest_tri(ray_start,
- ray_normal,
- node->bm_orco[t[0]],
- node->bm_orco[t[1]],
- node->bm_orco[t[2]],
- depth,
- dist_sq);
+ BKE_pbvh_bmesh_check_tris(pbvh, node);
+ PBVHTriBuf *tribuf = node->tribuf;
+ const int cd_dyn_vert = pbvh->cd_dyn_vert;
+
+ for (int i = 0; i < tribuf->tottri; i++) {
+ PBVHTri *tri = tribuf->tris + i;
+ BMFace *f = (BMFace *)tri->f.i;
+
+ if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ continue;
}
- }
- else {
- GSetIterator gs_iter;
- GSET_ITER (gs_iter, node->bm_faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+ BMVert *v1 = (BMVert *)tribuf->verts[tri->v[0]].i;
+ BMVert *v2 = (BMVert *)tribuf->verts[tri->v[1]].i;
+ BMVert *v3 = (BMVert *)tribuf->verts[tri->v[2]].i;
- BLI_assert(f->len == 3);
- if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
- BMVert *v_tri[3];
+ float *co1, *co2, *co3;
- BM_face_as_array_vert_tri(f, v_tri);
- hit |= ray_face_nearest_tri(
- ray_start, ray_normal, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co, depth, dist_sq);
- }
+ if (use_original) {
+ BKE_pbvh_bmesh_check_origdata(pbvh, v1, stroke_id);
+ BKE_pbvh_bmesh_check_origdata(pbvh, v2, stroke_id);
+ BKE_pbvh_bmesh_check_origdata(pbvh, v3, stroke_id);
+
+ co1 = BKE_PBVH_DYNVERT(cd_dyn_vert, v1)->origco;
+ co2 = BKE_PBVH_DYNVERT(cd_dyn_vert, v2)->origco;
+ co3 = BKE_PBVH_DYNVERT(cd_dyn_vert, v3)->origco;
}
+ else {
+ co1 = v1->co;
+ co2 = v2->co;
+ co3 = v3->co;
+ }
+
+ hit |= ray_face_nearest_tri(ray_start, ray_normal, co1, co2, co3, depth, dist_sq);
}
return hit;
}
+typedef struct UpdateNormalsTaskData {
+ PBVHNode **nodes;
+ int totnode;
+} UpdateNormalsTaskData;
+
+static void pbvh_update_normals_task_cb(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ BMVert *v;
+ BMFace *f;
+ UpdateNormalsTaskData *data = (UpdateNormalsTaskData *)userdata;
+ PBVHNode *node = data->nodes[n];
+
+ node->flag |= PBVH_UpdateCurvatureDir;
+
+ TGSET_ITER (f, node->bm_faces) {
+ BM_face_normal_update(f);
+ }
+ TGSET_ITER_END
+
+ TGSET_ITER (v, node->bm_unique_verts) {
+ // BM_vert_normal_update(v);
+ // optimized loop
+ BMEdge *e = v->e;
+
+ zero_v3(v->no);
+
+ if (!e) {
+ continue;
+ }
+
+ do {
+ BMLoop *l = e->l;
+
+ if (!l) {
+ e = v == e->v1 ? e->v1_disk_link.next : e->v2_disk_link.next;
+ continue;
+ }
+
+ do {
+ v->no[0] += l->f->no[0];
+ v->no[1] += l->f->no[1];
+ v->no[2] += l->f->no[2];
+
+ l = l->radial_next;
+ } while (l != e->l);
+
+ e = v == e->v1 ? e->v1_disk_link.next : e->v2_disk_link.next;
+ } while (e != v->e);
+
+ normalize_v3(v->no);
+ }
+ TGSET_ITER_END
+
+ node->flag &= ~PBVH_UpdateNormals;
+}
+
void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode)
{
+ TaskParallelSettings settings;
+ UpdateNormalsTaskData data = {nodes, totnode};
+
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_task_cb, &settings);
+
+#if 0 // in theory we shouldn't need to update normals in bm_other_verts.
+ for (int i=0; i<totnode; i++) {
+ PBVHNode *node = nodes[i];
+
+ TGSET_ITER (v, node->bm_other_verts) {
+ BM_vert_normal_update(v);
+ }
+ TGSET_ITER_END
+ }
+#endif
+}
+
+static void pbvh_bmesh_normals_update_old(PBVHNode **nodes, int totnode)
+{
for (int n = 0; n < totnode; n++) {
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;
}
}
@@ -1817,12 +3491,12 @@ 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->flag = PBVH_Leaf | PBVH_UpdateTris;
+ 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 +3507,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 +3515,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);
}
}
@@ -1869,32 +3543,83 @@ static void pbvh_bmesh_create_nodes_fast_recursive(
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_UpdateCurvatureDir;
}
}
/***************************** Public API *****************************/
+/*Used by symmetrize to update boundary flags*/
+void BKE_pbvh_recalc_bmesh_boundary(PBVH *pbvh)
+{
+ BMVert *v;
+ BMIter iter;
+
+ BM_ITER_MESH (v, &iter, pbvh->bm, BM_VERTS_OF_MESH) {
+ MDynTopoVert *mv = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v);
+
+ if (BM_vert_is_boundary(v)) {
+ mv->flag |= DYNVERT_BOUNDARY;
+ }
+ else {
+ mv->flag &= ~DYNVERT_BOUNDARY;
+ }
+ }
+}
+
/* Build a PBVH from a BMesh */
void BKE_pbvh_build_bmesh(PBVH *pbvh,
BMesh *bm,
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_dyn_vert)
{
pbvh->cd_vert_node_offset = cd_vert_node_offset;
pbvh->cd_face_node_offset = cd_face_node_offset;
+ pbvh->cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
+ pbvh->cd_dyn_vert = cd_dyn_vert;
+
pbvh->bm = bm;
- BKE_pbvh_bmesh_detail_size_set(pbvh, 0.75);
+ BKE_pbvh_bmesh_detail_size_set(pbvh, 0.75f, 0.4f);
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);
+
+ pbvh->depth_limit = 18;
/* TODO: choose leaf limit better */
- pbvh->leaf_limit = 100;
+ pbvh->leaf_limit = 1000;
+
+ BMIter iter;
+ BMVert *v;
+
+ int cd_vcol_offset = CustomData_get_offset(&bm->vdata, CD_PROP_COLOR);
+
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ MDynTopoVert *mv = BKE_PBVH_DYNVERT(cd_dyn_vert, v);
+ mv->flag = 0;
+
+ if (BM_vert_is_boundary(v)) {
+ mv->flag |= DYNVERT_BOUNDARY;
+ }
+
+ copy_v3_v3(mv->origco, v->co);
+ copy_v3_v3(mv->origno, v->no);
+
+ if (cd_vcol_offset >= 0) {
+ MPropCol *c1 = BM_ELEM_CD_GET_VOID_P(v, cd_vcol_offset);
+ copy_v4_v4(mv->origcolor, c1->color);
+ }
+ else {
+ zero_v4(mv->origcolor);
+ }
+ }
if (smooth_shading) {
pbvh->flags |= PBVH_DYNTOPO_SMOOTH_SHADING;
}
@@ -1904,7 +3629,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 +3650,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 +3676,245 @@ 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,
+ DyntopoMaskCB mask_cb,
+ void *mask_cb_data)
+{
+ 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) {
+ node->flag |= PBVH_UpdateCurvatureDir;
+ undopush(node, searchdata);
+
+ BKE_pbvh_node_mark_topology_update(pbvh->nodes + i);
+ }
+ }
+
+ modified = modified || BKE_pbvh_bmesh_update_topology(pbvh,
+ mode,
+ center,
+ view_normal,
+ radius,
+ use_frontface,
+ use_projected,
+ sym_axis,
+ updatePBVH,
+ mask_cb,
+ mask_cb_data);
+
+ return modified;
+}
+
+// this function is being buggy under clang's optimizer, at least on windows
+#ifdef __clang__
+# define CLANG_OPT_BUG __attribute__((optnone))
+#else
+# define CLANG_OPT_BUG
+#endif
+
+CLANG_OPT_BUG static bool cleanup_valence_3_4(PBVH *pbvh,
+ const float center[3],
+ const float view_normal[3],
+ float radius,
+ const bool use_frontface,
+ const bool use_projected)
+{
+ bool modified = false;
+
+ float radius2 = radius * 1.25;
+ float rsqr = radius2 * radius2;
+
+ GSet *vset = BLI_gset_ptr_new("vset");
+
+ for (int n = 0; n < pbvh->totnode; n++) {
+ PBVHNode *node = pbvh->nodes + n;
+
+ /* Check leaf nodes marked for topology update */
+ bool ok = (node->flag & PBVH_Leaf) && (node->flag & PBVH_UpdateTopology);
+ ok = ok && !(node->flag & (PBVH_FullyHidden | PBVH_Delete));
+
+ if (!ok) {
+ continue;
+ }
+
+ BMVert *v;
+
+ TGSET_ITER (v, node->bm_unique_verts) {
+ if (len_squared_v3v3(v->co, center) >= rsqr || !v->e) {
+ continue;
+ }
+
+ const int val = BM_vert_edge_count(v);
+ if (val != 4 && val != 3) {
+ continue;
+ }
+
+ BMIter iter;
+ BMLoop *l;
+ BMLoop *ls[4];
+ BMVert *vs[4];
+
+ l = v->e->l;
+
+ if (!l) {
+ continue;
+ }
+
+ if (l->v != v) {
+ l = l->next;
+ }
+
+ bool bad = false;
+ int i = 0;
+
+ for (int j = 0; j < val; j++) {
+ ls[i++] = l->v == v ? l->next : l;
+
+ l = l->prev->radial_next;
+
+ if (l->v != v) {
+ l = l->next;
+ }
+
+ if (l->radial_next == l || l->radial_next->radial_next != l) {
+ bad = true;
+ break;
+ }
+
+ for (int k = 0; k < j; k++) {
+ if (ls[k]->v == ls[j]->v) {
+ if (ls[j]->next->v != v) {
+ ls[j] = ls[j]->next;
+ }
+ else {
+ bad = true;
+ break;
+ }
+ }
+
+ if (ls[k]->f == ls[j]->f) {
+ bad = true;
+ break;
+ }
+ }
+ }
+
+ if (bad) {
+ continue;
+ }
+
+ int ni = BM_ELEM_CD_GET_INT(v, pbvh->cd_vert_node_offset);
+
+ if (ni >= 0 && BLI_table_gset_haskey(pbvh->nodes[ni].bm_other_verts, v)) {
+ printf("error!\n");
+ BLI_table_gset_remove(pbvh->nodes[ni].bm_other_verts, v, NULL);
+ }
+
+ BM_log_vert_removed(pbvh->bm_log, v, pbvh->cd_vert_mask_offset);
+ pbvh_bmesh_vert_remove(pbvh, v);
+
+ BMFace *f;
+ BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
+ int ni2 = BM_ELEM_CD_GET_INT(f, pbvh->cd_face_node_offset);
+
+ if (ni2 != DYNTOPO_NODE_NONE) {
+ PBVHNode *node2 = pbvh->nodes + ni2;
+
+ // BLI_table_gset_remove(node2->bm_unique_verts, v, NULL);
+ // BLI_table_gset_remove(node2->bm_other_verts, v, NULL);
+
+ pbvh_bmesh_face_remove(pbvh, f, true, true);
+ }
+ }
+
+ modified = true;
+
+ l = v->e->l;
+
+ vs[0] = ls[0]->v;
+ vs[1] = ls[1]->v;
+ vs[2] = ls[2]->v;
+
+ BMFace *f1 = NULL;
+ if (vs[0] != vs[1] && vs[1] != vs[2] && vs[0] != vs[2]) {
+ f1 = pbvh_bmesh_face_create(pbvh, n, vs, NULL, l->f, false, false);
+ normal_tri_v3(
+ f1->no, f1->l_first->v->co, f1->l_first->next->v->co, f1->l_first->prev->v->co);
+ }
+ else {
+ // printf("eek1!\n");
+ }
+
+ if (val == 4 && vs[0] != vs[2] && vs[2] != vs[3] && vs[0] != vs[3]) {
+ vs[0] = ls[0]->v;
+ vs[1] = ls[2]->v;
+ vs[2] = ls[3]->v;
+
+ BMFace *f2 = pbvh_bmesh_face_create(pbvh, n, vs, NULL, v->e->l->f, false, false);
+
+ CustomData_bmesh_swap_data_simple(
+ &pbvh->bm->ldata, &f2->l_first->prev->head.data, &ls[3]->head.data);
+
+ CustomData_bmesh_copy_data(
+ &pbvh->bm->ldata, &pbvh->bm->ldata, ls[0]->head.data, &f2->l_first->head.data);
+ CustomData_bmesh_copy_data(
+ &pbvh->bm->ldata, &pbvh->bm->ldata, ls[2]->head.data, &f2->l_first->next->head.data);
+
+ normal_tri_v3(
+ f2->no, f2->l_first->v->co, f2->l_first->next->v->co, f2->l_first->prev->v->co);
+ BM_log_face_added(pbvh->bm_log, f2);
+ }
+
+ if (f1) {
+ CustomData_bmesh_swap_data_simple(
+ &pbvh->bm->ldata, &f1->l_first->head.data, &ls[0]->head.data);
+ CustomData_bmesh_swap_data_simple(
+ &pbvh->bm->ldata, &f1->l_first->next->head.data, &ls[1]->head.data);
+ CustomData_bmesh_swap_data_simple(
+ &pbvh->bm->ldata, &f1->l_first->prev->head.data, &ls[2]->head.data);
+
+ BM_log_face_added(pbvh->bm_log, f1);
+ }
+
+ BM_vert_kill(pbvh->bm, v);
+ }
+ TGSET_ITER_END
+ }
+
+ BLI_gset_free(vset, NULL);
+
+ if (modified) {
+ pbvh->bm->elem_index_dirty |= BM_VERT | BM_FACE | BM_EDGE;
+ pbvh->bm->elem_table_dirty |= BM_VERT | BM_FACE | BM_EDGE;
+ }
+
+ return modified;
+}
+
/* Collapse short edges, subdivide long edges */
bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
PBVHTopologyUpdateMode mode,
@@ -1960,14 +3922,30 @@ 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,
+ DyntopoMaskCB mask_cb,
+ void *mask_cb_data)
{
+ /*
+ 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);
const int cd_vert_mask_offset = CustomData_get_offset(&pbvh->bm->vdata, CD_PAINT_MASK);
const int cd_vert_node_offset = pbvh->cd_vert_node_offset;
const int cd_face_node_offset = pbvh->cd_face_node_offset;
+ const int cd_dyn_vert = pbvh->cd_dyn_vert;
+ float ratio = 1.0f;
bool modified = false;
@@ -1975,52 +3953,158 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
BLI_assert(len_squared_v3(view_normal) != 0.0f);
}
+ EdgeQueueContext eq_ctx = {
+ NULL,
+ NULL,
+ pbvh->bm,
+ mask_cb,
+ mask_cb_data,
+
+ cd_dyn_vert,
+ cd_vert_mask_offset,
+ cd_vert_node_offset,
+ cd_face_node_offset,
+ .avg_elen = 0.0f,
+ .max_elen = -1e17,
+ .min_elen = 1e17,
+ .totedge = 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);
- EdgeQueueContext eq_ctx = {
- &q,
- queue_pool,
- pbvh->bm,
- cd_vert_mask_offset,
- cd_vert_node_offset,
- cd_face_node_offset,
- };
+
+ eq_ctx.q = &q;
+ eq_ctx.pool = queue_pool;
short_edge_queue_create(
&eq_ctx, pbvh, center, view_normal, radius, use_frontface, use_projected);
- modified |= pbvh_bmesh_collapse_short_edges(&eq_ctx, pbvh, &deleted_faces);
+
+# ifdef SKINNY_EDGE_FIX
+ // prevent remesher thrashing by throttling edge splitting in pathological case of skinny edges
+ float avg_elen = eq_ctx.avg_elen;
+ if (eq_ctx.totedge > 0.0f) {
+ avg_elen /= eq_ctx.totedge;
+
+ float emax = eq_ctx.max_elen;
+ if (emax == 0.0f) {
+ emax = 0.0001f;
+ }
+
+ if (pbvh->bm_min_edge_len > 0.0f && avg_elen > 0.0f) {
+ ratio = avg_elen / (pbvh->bm_min_edge_len * 0.5 + emax * 0.5);
+ ratio = MAX2(ratio, 0.25f);
+ ratio = MIN2(ratio, 5.0f);
+ }
+ }
+# endif
+
+ int max_steps = (int)((float)DYNTOPO_MAX_ITER * ratio);
+
+ check_nodes(pbvh);
+ modified |= pbvh_bmesh_collapse_short_edges(&eq_ctx, pbvh, &deleted_faces, max_steps);
+ check_nodes(pbvh);
+
BLI_heapsimple_free(q.heap, NULL);
+ if (q.elems) {
+ MEM_freeN(q.elems);
+ }
BLI_mempool_destroy(queue_pool);
}
if (mode & PBVH_Subdivide) {
EdgeQueue q;
BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *) * 2, 0, 128, BLI_MEMPOOL_NOP);
- EdgeQueueContext eq_ctx = {
- &q,
- queue_pool,
- pbvh->bm,
- cd_vert_mask_offset,
- cd_vert_node_offset,
- cd_face_node_offset,
- };
+
+ eq_ctx.q = &q;
+ eq_ctx.pool = queue_pool;
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);
+
+# ifdef SKINNY_EDGE_FIX
+ // prevent remesher thrashing by throttling edge splitting in pathological case of skinny edges
+ float avg_elen = eq_ctx.avg_elen;
+ if (eq_ctx.totedge > 0.0f) {
+ avg_elen /= eq_ctx.totedge;
+
+ float emin = eq_ctx.min_elen;
+ if (emin == 0.0f) {
+ emin = 0.0001f;
+ }
+
+ if (avg_elen > 0.0f) {
+ ratio = (pbvh->bm_max_edge_len * 0.5 + emin * 0.5) / avg_elen;
+ ratio = MAX2(ratio, 0.05f);
+ ratio = MIN2(ratio, 1.0f);
+ }
+ }
+# endif
+
+ int max_steps = (int)((float)DYNTOPO_MAX_ITER * ratio);
+
+ check_nodes(pbvh);
+ modified |= pbvh_bmesh_subdivide_long_edges(&eq_ctx, pbvh, &edge_loops, max_steps);
+ check_nodes(pbvh);
+
+ if (q.elems) {
+ MEM_freeN(q.elems);
+ }
BLI_heapsimple_free(q.heap, NULL);
BLI_mempool_destroy(queue_pool);
}
- /* Unmark nodes */
- for (int n = 0; n < pbvh->totnode; n++) {
- PBVHNode *node = &pbvh->nodes[n];
+#endif
+ if (mode & PBVH_Cleanup) {
+ check_nodes(pbvh);
+ modified |= cleanup_valence_3_4(
+ pbvh, center, view_normal, radius, use_frontface, use_projected);
+ check_nodes(pbvh);
+ }
+
+ if (modified) {
+
+#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
+
+ // avoid potential infinite loops
+ const int totnode = pbvh->totnode;
+
+ for (int i = 0; i < totnode; i++) {
+ PBVHNode *node = pbvh->nodes + i;
+
+ if ((node->flag & PBVH_Leaf) && (node->flag & PBVH_UpdateTopology) &&
+ !(node->flag & PBVH_FullyHidden)) {
+
+ node->flag &= ~PBVH_UpdateTopology;
- if (node->flag & PBVH_Leaf && node->flag & PBVH_UpdateTopology) {
- 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;
+ }
}
}
+
BLI_buffer_free(&edge_loops);
BLI_buffer_free(&deleted_faces);
@@ -2031,75 +4115,714 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
return modified;
}
+static void pbvh_free_tribuf(PBVHTriBuf *tribuf)
+{
+ MEM_SAFE_FREE(tribuf->verts);
+ MEM_SAFE_FREE(tribuf->tris);
+ MEM_SAFE_FREE(tribuf->loops);
+
+ tribuf->verts = NULL;
+ tribuf->tris = NULL;
+ tribuf->loops = NULL;
+
+ tribuf->verts_size = 0;
+ tribuf->tris_size = 0;
+}
+
+PBVHTriBuf *BKE_pbvh_bmesh_get_tris(PBVH *pbvh, PBVHNode *node)
+{
+ BKE_pbvh_bmesh_check_tris(pbvh, node);
+
+ return node->tribuf;
+}
+
+void BKE_pbvh_bmesh_free_tris(PBVH *pbvh, PBVHNode *node)
+{
+ if (node->tribuf) {
+ pbvh_free_tribuf(node->tribuf);
+ MEM_freeN(node->tribuf);
+ node->tribuf = NULL;
+ }
+
+ if (node->tri_buffers) {
+ for (int i = 0; i < node->tot_tri_buffers; i++) {
+ pbvh_free_tribuf(node->tri_buffers + i);
+ }
+
+ MEM_SAFE_FREE(node->tri_buffers);
+
+ node->tri_buffers = NULL;
+ node->tot_tri_buffers = 0;
+ }
+}
+
+/*
+generate triangle buffers with split uv islands.
+currently unused (and untested).
+*/
+static bool pbvh_bmesh_split_tris(PBVH *pbvh, PBVHNode *node)
+{
+ BMFace *f;
+
+ BM_mesh_elem_index_ensure(pbvh->bm, BM_VERT | BM_FACE);
+
+ // split by uvs
+ int layeri = CustomData_get_layer_index(&pbvh->bm->ldata, CD_MLOOPUV);
+ if (layeri < 0) {
+ return false;
+ }
+
+ int totlayer = 0;
+
+ while (layeri < pbvh->bm->ldata.totlayer && pbvh->bm->ldata.layers[layeri].type == CD_MLOOPUV) {
+ totlayer++;
+ layeri++;
+ }
+
+ const int cd_uv = pbvh->bm->ldata.layers[layeri].offset;
+ const int cd_size = CustomData_sizeof(CD_MLOOPUV);
+
+ SculptVertRef *verts = NULL;
+ PBVHTri *tris = NULL;
+ intptr_t *loops = NULL;
+
+ BLI_array_declare(verts);
+ BLI_array_declare(tris);
+ BLI_array_declare(loops);
+
+ TGSET_ITER (f, node->bm_faces) {
+ BMLoop *l = f->l_first;
+
+ do {
+ l->head.index = -1;
+ l = l->next;
+ } while (l != f->l_first);
+ }
+ TGSET_ITER_END
+
+ int vi = 0;
+
+ TGSET_ITER (f, node->bm_faces) {
+ BMLoop *l = f->l_first;
+
+ do {
+ if (l->head.index >= 0) {
+ continue;
+ }
+
+ l->head.index = vi++;
+ BLI_array_append(loops, (intptr_t)l);
+
+ SculptVertRef sv = {(intptr_t)l->v};
+ BLI_array_append(verts, sv);
+
+ BMIter iter;
+ BMLoop *l2;
+
+ BM_ITER_ELEM (l2, &iter, l, BM_LOOPS_OF_VERT) {
+ bool ok = true;
+
+ for (int i = 0; i < totlayer; i++) {
+ MLoopUV *uv1 = BM_ELEM_CD_GET_VOID_P(l, cd_uv + cd_size * i);
+ MLoopUV *uv2 = BM_ELEM_CD_GET_VOID_P(l2, cd_uv + cd_size * i);
+
+ if (len_v3v3(uv1->uv, uv2->uv) > 0.001) {
+ ok = false;
+ break;
+ }
+ }
+
+ if (ok) {
+ l2->head.index = l->head.index;
+ }
+ }
+ } while (l != f->l_first);
+ }
+ TGSET_ITER_END
+
+ TGSET_ITER (f, node->bm_faces) {
+ BMLoop *l1 = f->l_first, *l2 = f->l_first->next, *l3 = f->l_first->prev;
+
+ PBVHTri tri;
+ tri.f.i = (intptr_t)f;
+
+ tri.v[0] = l1->head.index;
+ tri.v[1] = l2->head.index;
+ tri.v[2] = l3->head.index;
+
+ copy_v3_v3(tri.no, f->no);
+ BLI_array_append(tris, tri);
+ }
+ TGSET_ITER_END
+
+ if (node->tribuf) {
+ MEM_SAFE_FREE(node->tribuf->verts);
+ MEM_SAFE_FREE(node->tribuf->tris);
+ MEM_SAFE_FREE(node->tribuf->loops);
+
+ node->tribuf->tottri = 0;
+ node->tribuf->tris = NULL;
+ }
+ else {
+ node->tribuf = MEM_callocN(sizeof(*node->tribuf), "node->tribuf");
+ }
+
+ node->tribuf->verts = verts;
+ node->tribuf->loops = loops;
+ node->tribuf->tris = tris;
+
+ node->tribuf->tottri = BLI_array_len(tris);
+ node->tribuf->totvert = BLI_array_len(verts);
+ node->tribuf->totloop = BLI_array_len(loops);
+
+ return true;
+}
+
+BLI_INLINE PBVHTri *pbvh_tribuf_add_tri(PBVHTriBuf *tribuf)
+{
+ tribuf->tottri++;
+
+ if (tribuf->tottri >= tribuf->tris_size) {
+ size_t newsize = (size_t)32 + (size_t)tribuf->tris_size + (size_t)(tribuf->tris_size >> 1);
+
+ if (!tribuf->tris) {
+ tribuf->tris = MEM_mallocN(sizeof(*tribuf->tris) * newsize, "tribuf tris");
+ }
+ else {
+ tribuf->tris = MEM_reallocN_id(tribuf->tris, sizeof(*tribuf->tris) * newsize, "tribuf tris");
+ }
+
+ tribuf->tris_size = newsize;
+ }
+
+ return tribuf->tris + tribuf->tottri - 1;
+}
+
+BLI_INLINE void pbvh_tribuf_add_vert(PBVHTriBuf *tribuf, SculptVertRef vertex)
+{
+ tribuf->totvert++;
+
+ if (tribuf->totvert >= tribuf->verts_size) {
+ size_t newsize = (size_t)32 + (size_t)(tribuf->verts_size << 1);
+
+ if (!tribuf->verts) {
+ tribuf->verts = MEM_mallocN(sizeof(*tribuf->verts) * newsize, "tribuf verts");
+ }
+ else {
+ tribuf->verts = MEM_reallocN_id(
+ tribuf->verts, sizeof(*tribuf->verts) * newsize, "tribuf verts");
+ }
+
+ tribuf->verts_size = newsize;
+ }
+
+ tribuf->verts[tribuf->totvert - 1] = vertex;
+}
+
/* In order to perform operations on the original node coordinates
* (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)
+bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
{
- /* Skip if original coords/triangles are already saved */
- if (node->bm_orco) {
- return;
+ BMesh *bm = pbvh->bm;
+
+ if (!(node->flag & PBVH_UpdateTris) && node->tribuf) {
+ return false;
}
- const int totvert = BLI_gset_len(node->bm_unique_verts) + BLI_gset_len(node->bm_other_verts);
+ GHash *vmap = BLI_ghash_ptr_new("pbvh_bmesh.c vmap");
+ GHash *mat_vmaps[MAXMAT];
- const int tottri = BLI_gset_len(node->bm_faces);
+ int mat_map[MAXMAT];
- node->bm_orco = MEM_mallocN(sizeof(*node->bm_orco) * totvert, __func__);
- node->bm_ortri = MEM_mallocN(sizeof(*node->bm_ortri) * tottri, __func__);
+ for (int i = 0; i < MAXMAT; i++) {
+ mat_map[i] = -1;
+ mat_vmaps[i] = NULL;
+ }
- /* 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);
- 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);
- copy_v3_v3(node->bm_orco[i], v->co);
- BM_elem_index_set(v, i); /* set_dirty! */
- i++;
+ if (node->tribuf) {
+ pbvh_free_tribuf(node->tribuf);
+ }
+ else {
+ node->tribuf = MEM_callocN(sizeof(*node->tribuf), "node->tribuf");
}
- /* 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);
+ PBVHTriBuf *tribufs = NULL; // material-specific tribuffers
+ BLI_array_declare(tribufs);
+ node->tribuf->mat_nr = 0;
+ node->tribuf->tottri = 0;
+ node->tribuf->totvert = 0;
+ node->tribuf->totloop = 0;
+
+ node->flag &= ~PBVH_UpdateTris;
+
+ BMFace *f;
+
+ float min[3], max[3];
+
+ INIT_MINMAX(min, max);
+
+ TGSET_ITER (f, node->bm_faces) {
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
continue;
}
-#if 0
- BMIter bm_iter;
- BMVert *v;
+ PBVHTri *tri = pbvh_tribuf_add_tri(node->tribuf);
+ const int mat_nr = f->mat_nr;
+
+ if (mat_map[mat_nr] == -1) {
+ PBVHTriBuf _tribuf = {0};
+
+ _tribuf.mat_nr = mat_nr;
+
+ mat_map[mat_nr] = BLI_array_len(tribufs);
+ mat_vmaps[mat_nr] = BLI_ghash_ptr_new("pbvh_bmesh.c vmap");
+
+ BLI_array_append(tribufs, _tribuf);
+ }
+
+ PBVHTriBuf *mat_tribuf = tribufs + mat_map[mat_nr];
+ PBVHTri *mat_tri = pbvh_tribuf_add_tri(mat_tribuf);
+
+ BMLoop *l = f->l_first;
int j = 0;
- BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) {
- node->bm_ortri[i][j] = BM_elem_index_get(v);
+
+ do {
+ void **val = NULL;
+
+ if (!BLI_ghash_ensure_p(vmap, l->v, &val)) {
+ SculptVertRef sv = {(intptr_t)l->v};
+
+ minmax_v3v3_v3(min, max, l->v->co);
+
+ *val = (void *)node->tribuf->totvert;
+ pbvh_tribuf_add_vert(node->tribuf, sv);
+ }
+
+ tri->v[j] = (intptr_t)val[0];
+
+ val = NULL;
+ if (!BLI_ghash_ensure_p(mat_vmaps[mat_nr], l->v, &val)) {
+ SculptVertRef sv = {(intptr_t)l->v};
+
+ minmax_v3v3_v3(min, max, l->v->co);
+
+ *val = (void *)mat_tribuf->totvert;
+ pbvh_tribuf_add_vert(mat_tribuf, sv);
+ }
+
+ mat_tri->v[j] = (intptr_t)val[0];
+
j++;
+
+ if (j >= 3) {
+ break;
+ }
+
+ l = l->next;
+ } while (l != f->l_first);
+
+ copy_v3_v3(tri->no, f->no);
+ tri->f.i = (intptr_t)f;
+ }
+ TGSET_ITER_END
+
+ bm->elem_index_dirty |= BM_VERT;
+
+ node->tri_buffers = tribufs;
+ node->tot_tri_buffers = BLI_array_len(tribufs);
+
+ if (node->tribuf->totvert) {
+ copy_v3_v3(node->tribuf->min, min);
+ copy_v3_v3(node->tribuf->max, max);
+ }
+ else {
+ zero_v3(node->tribuf->min);
+ zero_v3(node->tribuf->max);
+ }
+
+ BLI_ghash_free(vmap, NULL, NULL);
+ for (int i = 0; i < MAXMAT; i++) {
+ if (mat_vmaps[i]) {
+ BLI_ghash_free(mat_vmaps[i], NULL, NULL);
}
-#else
- bm_face_as_array_index_tri(f, node->bm_ortri[i]);
+ }
+
+ return true;
+}
+
+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_correct_tree(PBVH *pbvh, PBVHNode *node, PBVHNode *parent)
+{
+ const int size_lower = pbvh->leaf_limit - (pbvh->leaf_limit >> 1);
+
+ if (node->flag & PBVH_Leaf) {
+ // pbvh_bmesh_node_limit_ensure(pbvh, (int)(node - pbvh->nodes));
+ return;
+ }
+
+ 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 | PBVH_UpdateTris;
+
+ TableGSet *other = BLI_table_gset_new(__func__);
+ BMVert *v;
+
+ node->children_offset = 0;
+
+ pbvh_free_all_draw_buffers(node);
+
+ // 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_correct_tree(pbvh, child, node);
+ }
+}
+
+static void pbvh_bmesh_join_nodes(PBVH *bvh)
+{
+ if (bvh->totnode < 2) {
+ return;
+ }
+
+ pbvh_count_subtree_verts(bvh, bvh->nodes);
+ BKE_pbvh_bmesh_correct_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 | PBVH_UpdateTris;
+ 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");
+ n3->tribuf = NULL;
+ }
+ else if ((n1->flag & PBVH_Delete) && (n2->flag & PBVH_Delete)) {
+ n->children_offset = 0;
+ n->flag |= PBVH_Leaf | PBVH_UpdateTris;
+
+ 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");
+ n->tribuf = NULL;
+ }
+ }
+ }
+
+ 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;
+ }
+
+ pbvh_free_all_draw_buffers(n);
+
+ 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->tribuf) {
+ BKE_pbvh_bmesh_free_tris(bvh, n);
+ }
+
+ 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
- i++;
+ }
+ }
+
+ // compact node array
+ j = 0;
+ for (int i = 0; i < bvh->totnode; i++) {
+ if (!(bvh->nodes[i].flag & PBVH_Delete)) {
+ if (bvh->nodes[i].children_offset >= bvh->totnode - 1) {
+ printf("error %i %i\n", i, bvh->nodes[i].children_offset);
+ continue;
+ }
+
+ 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;
+
+ // 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);
+ }
}
- node->bm_tot_ortri = i;
+
+ BLI_array_free(scratch);
+ MEM_freeN(map);
}
void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh)
{
- for (int i = 0; i < pbvh->totnode; i++) {
- PBVHNode *n = &pbvh->nodes[i];
- if (n->flag & PBVH_Leaf) {
- /* Free orco/ortri data */
- pbvh_bmesh_node_drop_orig(n);
+ check_heap();
+ int totnode = pbvh->totnode;
+
+ check_nodes(pbvh);
+ pbvh_bmesh_join_nodes(pbvh);
+ check_nodes(pbvh);
+
+ check_heap();
+
+ BKE_pbvh_update_bounds(pbvh, (PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw));
+
+ totnode = pbvh->totnode;
+
+ for (int i = 0; i < totnode; 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) {
/* Recursively split nodes that have gotten too many
* elements */
pbvh_bmesh_node_limit_ensure(pbvh, i);
@@ -2107,10 +4830,10 @@ void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh)
}
}
-void BKE_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size)
+void BKE_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size, float detail_range)
{
pbvh->bm_max_edge_len = detail_size;
- pbvh->bm_min_edge_len = pbvh->bm_max_edge_len * 0.4f;
+ pbvh->bm_min_edge_len = pbvh->bm_max_edge_len * detail_range;
}
void BKE_pbvh_node_mark_topology_update(PBVHNode *node)
@@ -2118,17 +4841,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 +4912,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 +4938,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 +4957,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 +4994,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 +5018,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 +5032,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 +5054,434 @@ 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_dyn_vert)
+{
+ 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_vcol_offset = CustomData_get_offset(&pbvh->bm->vdata, CD_PROP_COLOR);
+ pbvh->cd_dyn_vert = cd_dyn_vert;
+}
+
+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 = NULL;
+
+ 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);
+}
+
+BMesh *BKE_pbvh_reorder_bmesh(PBVH *pbvh)
+{
+ if (BKE_pbvh_type(pbvh) != PBVH_BMESH || pbvh->totnode == 0) {
+ return pbvh->bm;
+ }
+
+ // try to group memory allocations by node
+ struct {
+ BMEdge **edges;
+ int totedge;
+ BMVert **verts;
+ int totvert;
+ BMFace **faces;
+ int totface;
+ } *nodedata = MEM_callocN(sizeof(*nodedata) * pbvh->totnode, "nodedata");
+
+ BMIter iter;
+ int types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
+
+#define VISIT_TAG BM_ELEM_TAG
+
+ BM_mesh_elem_index_ensure(pbvh->bm, BM_VERT | BM_EDGE | BM_FACE);
+ BM_mesh_elem_table_ensure(pbvh->bm, BM_VERT | BM_EDGE | BM_FACE);
+
+ for (int i = 0; i < 3; i++) {
+ BMHeader *elem;
+
+ BM_ITER_MESH (elem, &iter, pbvh->bm, types[i]) {
+ elem->hflag &= ~VISIT_TAG;
+ }
+ }
+
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *node = pbvh->nodes + i;
+
+ if (!(node->flag & PBVH_Leaf)) {
+ continue;
+ }
+
+ BMVert **verts = nodedata[i].verts;
+ BMEdge **edges = nodedata[i].edges;
+ BMFace **faces = nodedata[i].faces;
+
+ BLI_array_declare(verts);
+ BLI_array_declare(edges);
+ BLI_array_declare(faces);
+
+ BMVert *v;
+ BMFace *f;
+
+ TGSET_ITER (v, node->bm_unique_verts) {
+ if (v->head.hflag & VISIT_TAG) {
+ continue;
+ }
+
+ v->head.hflag |= VISIT_TAG;
+ BLI_array_append(verts, v);
+
+ BMEdge *e = v->e;
+ do {
+ if (!(e->head.hflag & VISIT_TAG)) {
+ e->head.hflag |= VISIT_TAG;
+ BLI_array_append(edges, e);
+ }
+ e = v == e->v1 ? e->v1_disk_link.next : e->v2_disk_link.next;
+ } while (e != v->e);
+ }
+ TGSET_ITER_END;
+
+ TGSET_ITER (f, node->bm_faces) {
+ if (f->head.hflag & VISIT_TAG) {
+ continue;
+ }
+
+ BLI_array_append(faces, f);
+ f->head.hflag |= VISIT_TAG;
+ }
+ TGSET_ITER_END;
+
+ nodedata[i].verts = verts;
+ nodedata[i].edges = edges;
+ nodedata[i].faces = faces;
+
+ nodedata[i].totvert = BLI_array_len(verts);
+ nodedata[i].totedge = BLI_array_len(edges);
+ nodedata[i].totface = BLI_array_len(faces);
+ }
+
+ BMAllocTemplate templ = {
+ pbvh->bm->totvert, pbvh->bm->totedge, pbvh->bm->totloop, pbvh->bm->totface};
+ struct BMeshCreateParams params = {0};
+
+ BMesh *bm2 = BM_mesh_create(&templ, &params);
+
+ CustomData_copy_all_layout(&pbvh->bm->vdata, &bm2->vdata);
+ CustomData_copy_all_layout(&pbvh->bm->edata, &bm2->edata);
+ CustomData_copy_all_layout(&pbvh->bm->ldata, &bm2->ldata);
+ CustomData_copy_all_layout(&pbvh->bm->pdata, &bm2->pdata);
+
+ CustomData_bmesh_init_pool(&bm2->vdata, pbvh->bm->totvert, BM_VERT);
+ CustomData_bmesh_init_pool(&bm2->edata, pbvh->bm->totedge, BM_EDGE);
+ CustomData_bmesh_init_pool(&bm2->ldata, pbvh->bm->totloop, BM_LOOP);
+ CustomData_bmesh_init_pool(&bm2->pdata, pbvh->bm->totface, BM_FACE);
+
+ BMVert **verts = NULL;
+ BMEdge **edges = NULL;
+ BMFace **faces = NULL;
+ BLI_array_declare(verts);
+ BLI_array_declare(edges);
+ BLI_array_declare(faces);
+
+ for (int i = 0; i < pbvh->totnode; i++) {
+ for (int j = 0; j < nodedata[i].totvert; j++) {
+ BMVert *v1 = nodedata[i].verts[j];
+ BMVert *v2 = BM_vert_create(bm2, v1->co, NULL, BM_CREATE_NOP);
+ BM_elem_attrs_copy_ex(pbvh->bm, bm2, v1, v2, 0, 0L);
+
+ v2->head.index = v1->head.index = BLI_array_len(verts);
+ BLI_array_append(verts, v2);
+ }
+ }
+
+ for (int i = 0; i < pbvh->totnode; i++) {
+ for (int j = 0; j < nodedata[i].totedge; j++) {
+ BMEdge *e1 = nodedata[i].edges[j];
+ BMEdge *e2 = BM_edge_create(
+ bm2, verts[e1->v1->head.index], verts[e1->v2->head.index], NULL, BM_CREATE_NOP);
+ BM_elem_attrs_copy_ex(pbvh->bm, bm2, e1, e2, 0, 0L);
+
+ e2->head.index = e1->head.index = BLI_array_len(edges);
+ BLI_array_append(edges, e2);
+ }
+ }
+
+ BMVert **fvs = NULL;
+ BMEdge **fes = NULL;
+ BLI_array_declare(fvs);
+ BLI_array_declare(fes);
+
+ for (int i = 0; i < pbvh->totnode; i++) {
+ for (int j = 0; j < nodedata[i].totface; j++) {
+ BMFace *f1 = nodedata[i].faces[j];
+
+ BLI_array_clear(fvs);
+ BLI_array_clear(fes);
+
+ int totloop = 0;
+ BMLoop *l1 = f1->l_first;
+ do {
+ BLI_array_append(fvs, verts[l1->v->head.index]);
+ BLI_array_append(fes, edges[l1->e->head.index]);
+ l1 = l1->next;
+ totloop++;
+ } while (l1 != f1->l_first);
+
+ BMFace *f2 = BM_face_create(bm2, fvs, fes, totloop, NULL, BM_CREATE_NOP);
+ f1->head.index = f2->head.index = BLI_array_len(faces);
+ BLI_array_append(faces, f2);
+
+ // CustomData_bmesh_copy_data(&pbvh->bm->pdata, &bm2->pdata, f1->head.data,
+ // &f2->head.data);
+ BM_elem_attrs_copy_ex(pbvh->bm, bm2, f1, f2, 0, 0L);
+
+ BMLoop *l2 = f2->l_first;
+ do {
+ BM_elem_attrs_copy_ex(pbvh->bm, bm2, l1, l2, 0, 0L);
+
+ l1 = l1->next;
+ l2 = l2->next;
+ } while (l2 != f2->l_first);
+ }
+ }
+
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *node = pbvh->nodes + i;
+
+ if (!(node->flag & PBVH_Leaf)) {
+ continue;
+ }
+
+ int totunique = node->bm_unique_verts->length;
+ int totother = node->bm_other_verts->length;
+ int totface = node->bm_faces->length;
+
+ TableGSet *bm_faces = BLI_table_gset_new_ex("bm_faces", totface);
+ TableGSet *bm_other_verts = BLI_table_gset_new_ex("bm_other_verts", totunique);
+ TableGSet *bm_unique_verts = BLI_table_gset_new_ex("bm_unique_verts", totother);
+
+ BMVert *v;
+ BMFace *f;
+
+ TGSET_ITER (v, node->bm_unique_verts) {
+ BLI_table_gset_insert(bm_unique_verts, verts[v->head.index]);
+ }
+ TGSET_ITER_END;
+ TGSET_ITER (v, node->bm_other_verts) {
+ BLI_table_gset_insert(bm_other_verts, verts[v->head.index]);
+ }
+ TGSET_ITER_END;
+ TGSET_ITER (f, node->bm_faces) {
+ BLI_table_gset_insert(bm_faces, faces[f->head.index]);
+ }
+ TGSET_ITER_END;
+
+ BLI_table_gset_free(node->bm_faces, NULL);
+ BLI_table_gset_free(node->bm_other_verts, NULL);
+ BLI_table_gset_free(node->bm_unique_verts, NULL);
+
+ node->bm_faces = bm_faces;
+ node->bm_other_verts = bm_other_verts;
+ node->bm_unique_verts = bm_unique_verts;
+
+ node->flag |= PBVH_UpdateTris | PBVH_UpdateRedraw;
+ }
+
+ MEM_SAFE_FREE(fvs);
+ MEM_SAFE_FREE(fes);
+
+ for (int i = 0; i < pbvh->totnode; i++) {
+ MEM_SAFE_FREE(nodedata[i].verts);
+ MEM_SAFE_FREE(nodedata[i].edges);
+ MEM_SAFE_FREE(nodedata[i].faces);
+ }
+
+ MEM_SAFE_FREE(verts);
+ MEM_SAFE_FREE(edges);
+ MEM_SAFE_FREE(faces);
+
+ MEM_freeN(nodedata);
+
+ BM_mesh_free(pbvh->bm);
+ pbvh->bm = bm2;
+
+ return bm2;
+}
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index 84c4ae4dead..2c2ed4a3e2c 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -16,6 +16,9 @@
#pragma once
+#include "BLI_ghash.h"
+#include "DNA_material_types.h"
+
/** \file
* \ingroup bli
*/
@@ -35,6 +38,10 @@ typedef struct {
struct PBVHNode {
/* Opaque handle for drawing code */
struct GPU_PBVH_Buffers *draw_buffers;
+ struct GPU_PBVH_Buffers **mat_draw_buffers; // currently only used by pbvh_bmesh
+ int tot_mat_draw_buffers;
+
+ int id;
/* Voxel bounds */
BB vb;
@@ -43,6 +50,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 +94,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 +106,21 @@ struct PBVHNode {
PBVHProxyNode *proxies;
/* Dyntopo */
- GSet *bm_faces;
- GSet *bm_unique_verts;
- GSet *bm_other_verts;
- float (*bm_orco)[3];
- int (*bm_ortri)[3];
- int bm_tot_ortri;
+ TableGSet *bm_faces;
+ TableGSet *bm_unique_verts;
+ TableGSet *bm_other_verts;
+
+ PBVHTriBuf *tribuf; // all triangles
+ PBVHTriBuf *tri_buffers; // tribuffers, one per material used
+ int tot_tri_buffers;
+
+ int updategen;
/* 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 {
@@ -119,6 +133,8 @@ struct PBVH {
PBVHType type;
PBVHFlags flags;
+ int idgen;
+
PBVHNode *nodes;
int node_mem_count, totnode;
@@ -127,6 +143,7 @@ struct PBVH {
int totvert;
int leaf_limit;
+ int depth_limit;
/* Mesh data */
const struct Mesh *mesh;
@@ -168,14 +185,21 @@ struct PBVH {
BMesh *bm;
float bm_max_edge_len;
float bm_min_edge_len;
+
+ int cd_dyn_vert;
int cd_vert_node_offset;
int cd_face_node_offset;
+ int cd_vert_mask_offset;
+ int cd_vcol_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 */
@@ -218,19 +242,28 @@ bool ray_face_nearest_tri(const float ray_start[3],
void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag);
/* pbvh_bmesh.c */
-bool pbvh_bmesh_node_raycast(PBVHNode *node,
+bool pbvh_bmesh_node_raycast(PBVH *pbvh,
+ PBVHNode *node,
const float ray_start[3],
const float ray_normal[3],
struct IsectRayPrecalc *isect_precalc,
float *dist,
bool use_original,
- int *r_active_vertex_index,
- float *r_face_normal);
-bool pbvh_bmesh_node_nearest_to_ray(PBVHNode *node,
+ struct SculptVertRef *r_active_vertex_index,
+ struct SculptFaceRef *r_active_face_index,
+ float *r_face_normal,
+ int stroke_id);
+
+bool pbvh_bmesh_node_nearest_to_ray(PBVH *pbvh,
+ PBVHNode *node,
const float ray_start[3],
const float ray_normal[3],
float *depth,
float *dist_sq,
- bool use_original);
+ bool use_original,
+ int stroke_id);
void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode);
+
+void pbvh_free_all_draw_buffers(PBVHNode *node);
+void pbvh_update_free_all_draw_buffers(PBVH *pbvh, PBVHNode *node);
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index cc5a8536a5a..318acfc3892 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -2584,6 +2584,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..65d93ff126e 100644
--- a/source/blender/blenkernel/intern/subdiv_displacement_multires.c
+++ b/source/blender/blenkernel/intern/subdiv_displacement_multires.c
@@ -360,6 +360,7 @@ 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);
}