diff options
Diffstat (limited to 'source/blender/blenkernel')
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, ¶ms); + + 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); } |