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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Eagar <joeedh@gmail.com>2020-10-24 00:49:14 +0300
committerJoseph Eagar <joeedh@gmail.com>2020-10-24 00:49:14 +0300
commit4faa2b4bc9f56cc2ab7260e5d464fcee27a7adbb (patch)
tree8c95075d30d3ed21e86adf07060c5779b92f2c2b
parent0a66436fe5f26f8d7b6fb49396f21313fded8654 (diff)
Rebase branch
-rw-r--r--.clang-format4
-rw-r--r--source/blender/CMakeLists.txt1
-rw-r--r--source/blender/blenkernel/BKE_customdata.h9
-rw-r--r--source/blender/blenkernel/BKE_multires.h2
-rw-r--r--source/blender/blenkernel/BKE_paint.h35
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h192
-rw-r--r--source/blender/blenkernel/CMakeLists.txt3
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.c1
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c4
-rw-r--r--source/blender/blenkernel/intern/anim_data.c2
-rw-r--r--source/blender/blenkernel/intern/collection.c4
-rw-r--r--source/blender/blenkernel/intern/customdata.c161
-rw-r--r--source/blender/blenkernel/intern/lib_id.c2
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.cc232
-rw-r--r--source/blender/blenkernel/intern/object.c4
-rw-r--r--source/blender/blenkernel/intern/paint.c97
-rw-r--r--source/blender/blenkernel/intern/pbvh.c555
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c2
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h52
-rw-r--r--source/blender/blenlib/BLI_ghash.h57
-rw-r--r--source/blender/blenlib/BLI_smallhash.h297
-rw-r--r--source/blender/blenlib/BLI_span.hh65
-rw-r--r--source/blender/blenlib/BLI_threads.h11
-rw-r--r--source/blender/blenlib/CMakeLists.txt15
-rw-r--r--source/blender/blenlib/intern/BLI_ghash.c38
-rw-r--r--source/blender/blenlib/intern/math_boolean.cc16
-rw-r--r--source/blender/blenlib/intern/smallhash.c234
-rw-r--r--source/blender/blenlib/intern/task_pool.cc2
-rw-r--r--source/blender/blenlib/intern/threads.cc27
-rw-r--r--source/blender/blenloader/intern/versioning_280.c6
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.c19
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c9
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_convert.c6
-rw-r--r--source/blender/bmesh/operators/bmo_fill_grid.c1
-rw-r--r--source/blender/bmesh/operators/bmo_hull.c1
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_collapse.c2
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c2
-rw-r--r--source/blender/draw/intern/draw_hair.c14
-rw-r--r--source/blender/draw/intern/draw_hair_private.h2
-rw-r--r--source/blender/draw/intern/shaders/common_hair_lib.glsl75
-rw-r--r--source/blender/editors/interface/interface_template_search_menu.c1
-rw-r--r--source/blender/editors/mesh/editmesh_select_similar.c1
-rw-r--r--source/blender/editors/object/object_remesh.c2
-rw-r--r--source/blender/editors/screen/area.c1
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt2
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_hide.c92
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c1
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c1
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c395
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_automasking.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_boundary.c39
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c1
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_dyntopo.c197
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.c1
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_color.c1
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mask.c1
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mesh.c1
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h79
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_mask_expand.c7
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c1
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_paint_color.c1
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_pose.c25
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_smooth.c172
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_transform.c1
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c231
-rw-r--r--source/blender/editors/space_info/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_info/info_stats.c8
-rw-r--r--source/blender/gpu/CMakeLists.txt1
-rw-r--r--source/blender/gpu/GPU_buffers.h10
-rw-r--r--source/blender/gpu/GPU_vertex_buffer.h1
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c327
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h5
-rw-r--r--source/blender/makesdna/DNA_scene_defaults.h1
-rw-r--r--source/blender/makesdna/DNA_scene_types.h3
-rw-r--r--source/blender/makesrna/intern/rna_context.c2
-rw-r--r--source/blender/makesrna/intern/rna_object.c2
-rw-r--r--source/blender/makesrna/intern/rna_scene.c6
-rw-r--r--source/blender/python/gpu/gpu_py_offscreen.c17
79 files changed, 3297 insertions, 608 deletions
diff --git a/.clang-format b/.clang-format
index 8a992fea3a9..061137b6867 100644
--- a/.clang-format
+++ b/.clang-format
@@ -262,6 +262,10 @@ ForEachMacros:
- SET_SLOT_PROBING_BEGIN
- MAP_SLOT_PROBING_BEGIN
- VECTOR_SET_SLOT_PROBING_BEGIN
+ - TMS_ITER
+ - TM_ITER_VERT_TRIS
+ - TM_ITER_VERT_TRIEDGES
+ - TM_ITER_MESH
# Use once we bump the minimum version to version 8.
# # Without this string literals that in-line 'STRINGIFY' behave strangely (a bug?).
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index da6df831c0a..1335553effd 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -105,6 +105,7 @@ add_subdirectory(editors)
add_subdirectory(windowmanager)
add_subdirectory(blenkernel)
add_subdirectory(blenlib)
+add_subdirectory(trimesh)
add_subdirectory(bmesh)
add_subdirectory(draw)
add_subdirectory(render)
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 51650d161ea..48fa5304646 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -311,6 +311,15 @@ void CustomData_bmesh_interp(struct CustomData *data,
int count,
void *dst_block);
+struct TM_TriMesh;
+void CustomData_trimesh_init_pool(struct TM_TriMesh *tm, struct CustomData *data, int totelem, const char htype);
+bool CustomData_trimesh_merge(const struct CustomData *source,
+ struct CustomData *dest,
+ CustomDataMask mask,
+ eCDAllocType alloctype,
+ struct TM_TriMesh *bm,
+ const char htype);
+
/* swaps the data in the element corners, to new corners with indices as
* specified in corner_indices. for edges this is an array of length 2, for
* faces an array of length 4 */
diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h
index fbdfc5b76a7..d1e69e68b1e 100644
--- a/source/blender/blenkernel/BKE_multires.h
+++ b/source/blender/blenkernel/BKE_multires.h
@@ -95,6 +95,8 @@ struct Mesh *BKE_multires_create_mesh(struct Depsgraph *depsgraph,
struct Object *object,
struct MultiresModifierData *mmd);
+void BKE_multires_bmesh_space_set(struct Object *ob, struct BMesh *bm, int mode);
+
/* Get coordinates of a deformed base mesh which is an input to the given multires modifier.
* NOTE: The modifiers will be re-evaluated. */
float (*BKE_multires_create_deformed_base_mesh_vert_coords(struct Depsgraph *depsgraph,
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 150d0d9b011..a35dc63d9bd 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -23,6 +23,8 @@
* \ingroup bke
*/
+#include "BKE_pbvh.h"
+
#include "BLI_bitmap.h"
#include "BLI_utildefines.h"
#include "DNA_object_enums.h"
@@ -286,10 +288,10 @@ typedef struct SculptClothLengthConstraint {
* point, position for a previous state). In that case, elem_index_a and elem_index_b should be
* the same to avoid affecting two different vertices when solving the constraints.
* *elem_position points to the position which is owned by the element. */
- int elem_index_a;
+ SculptIdx elem_index_a;
float *elem_position_a;
- int elem_index_b;
+ SculptIdx elem_index_b;
float *elem_position_b;
float length;
@@ -342,7 +344,7 @@ typedef struct SculptPersistentBase {
typedef struct SculptVertexInfo {
/* Indexed by vertex, stores and ID of its topologically connected component. */
- int *connected_component;
+ SculptIdx *connected_component;
/* Indexed by base mesh vertex index, stores if that vertex is a boundary. */
BLI_bitmap *boundary;
@@ -350,7 +352,7 @@ typedef struct SculptVertexInfo {
typedef struct SculptBoundaryEditInfo {
/* Vertex index from where the topology propagation reached this vertex. */
- int original_vertex;
+ SculptIdx original_vertex;
/* How many steps were needed to reach this vertex from the boundary. */
int num_propagation_steps;
@@ -361,13 +363,13 @@ typedef struct SculptBoundaryEditInfo {
/* Edge for drawing the boundary preview in the cursor. */
typedef struct SculptBoundaryPreviewEdge {
- int v1;
- int v2;
+ SculptIdx v1;
+ SculptIdx v2;
} SculptBoundaryPreviewEdge;
typedef struct SculptBoundary {
/* Vertex indices of the active boundary. */
- int *vertices;
+ SculptIdx *vertices;
int vertices_capacity;
int num_vertices;
@@ -385,12 +387,12 @@ typedef struct SculptBoundary {
bool forms_loop;
/* Initial vertex in the boundary which is closest to the current sculpt active vertex. */
- int initial_vertex;
+ SculptIdx 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;
+ SculptIdx 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
@@ -430,8 +432,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;
-
+ SculptIdx *fake_neighbor_index;
} SculptFakeNeighbors;
/* Session data (mode-specific) */
@@ -470,6 +471,9 @@ typedef struct SculptSession {
* Face Set ID. Positive IDs are visible, negative IDs are hidden. */
int *face_sets;
+ struct TM_TriMesh *tm;
+ struct TriMeshLog *tm_log;
+
/* BMesh for dynamic topology sculpting */
struct BMesh *bm;
int cd_vert_node_offset;
@@ -500,7 +504,7 @@ typedef struct SculptSession {
struct FilterCache *filter_cache;
/* Cursor data and active vertex for tools */
- int active_vertex_index;
+ SculptIdx active_vertex_index;
int active_face_index;
int active_grid_index;
@@ -522,7 +526,7 @@ typedef struct SculptSession {
struct Scene *scene;
/* Dynamic mesh preview */
- int *preview_vert_index_list;
+ SculptIdx *preview_vert_index_list;
int preview_vert_index_count;
/* Pose Brush Preview */
@@ -579,7 +583,6 @@ typedef struct SculptSession {
* Set #Main.is_memfile_undo_flush_needed when enabling.
*/
char needs_flush_to_id;
-
} SculptSession;
void BKE_sculptsession_free(struct Object *ob);
@@ -588,6 +591,10 @@ void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss);
void BKE_sculptsession_bm_to_me(struct Object *ob, bool reorder);
void BKE_sculptsession_bm_to_me_for_render(struct Object *object);
+void BKE_sculptsession_tm_to_me(struct Object *ob, bool reorder);
+void BKE_sculptsession_tm_to_me_for_render(struct Object *object);
+
+
/* Create new color layer on object if it doesn't have one and if experimental feature set has
* sculpt vertex color enabled. Returns truth if new layer has been added, false otherwise. */
void BKE_sculpt_color_layer_create_if_needed(struct Object *object);
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index cd213b49c5b..6ae99aabe9b 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -23,6 +23,11 @@
#include "BLI_bitmap.h"
#include "BLI_ghash.h"
+#include "BLI_threadsafe_mempool.h"
+
+#include "stdint.h"
+
+typedef intptr_t SculptIdx;
/* For embedding CCGKey in iterator. */
#include "BKE_ccg.h"
@@ -53,6 +58,79 @@ struct TaskParallelTLS;
typedef struct PBVH PBVH;
typedef struct PBVHNode PBVHNode;
+//#define WITH_TRIMESH
+
+//#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;
+ SculptIdx *index;
+ float **ownercolor, (*color)[4];
+
+ ProxyKey (*neighbors)[MAX_PROXY_NEIGHBORS];
+
+ int size;
+ int datamask;
+
+ 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;
+ int index, newindex;
+} ProxyVertUpdateRec;
+
+# define PBVH_PROXY_DEFAULT CO | INDEX | MASK
+
+struct SculptSession;
+
+void BKE_pbvh_ensure_proxyarrays(struct SculptSession *ss, PBVH *pbvh, 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 SculptIdxs 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;
@@ -79,6 +157,7 @@ typedef enum {
PBVH_UpdateTopology = 1 << 13,
PBVH_UpdateColor = 1 << 14,
+ PBVH_Delete = 1 << 15,
} PBVHNodeFlags;
typedef struct PBVHFrustumPlanes {
@@ -86,6 +165,32 @@ typedef struct PBVHFrustumPlanes {
int num_planes;
} PBVHFrustumPlanes;
+typedef struct TMElemSet {
+ struct GHash *ptr_to_idx;
+ void **elems;
+ int size, length;
+ int cur;
+} TMElemSet;
+
+TMElemSet *TMElemSet_new();
+void TMElemSet_free(TMElemSet *ts);
+void TMElemSet_insert(TMElemSet *ts, void *elem);
+bool TMElemSet_add(TMElemSet *ts, void *elem);
+void TMElemSet_remove(TMElemSet *ts, void *elem, bool ignoreExist);
+bool TMElemSet_has(TMElemSet *ts, void *elem);
+
+#define TMS_ITER(v, ts) \
+ { \
+ int _i1; \
+ for (_i1 = 0; _i1 < ts->cur; _i1++) { \
+ if (!ts->elems[_i1]) \
+ continue; \
+ v = ts->elems[_i1];
+
+#define TMS_ITER_END \
+ } \
+ }
+
void BKE_pbvh_set_frustum_planes(PBVH *pbvh, PBVHFrustumPlanes *planes);
void BKE_pbvh_get_frustum_planes(PBVH *pbvh, PBVHFrustumPlanes *planes);
@@ -126,7 +231,15 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh,
struct BMLog *log,
const int cd_vert_node_offset,
const int cd_face_node_offset);
-void BKE_pbvh_free(PBVH *pbvh);
+void BKE_pbvh_build_trimesh(PBVH *bvh,
+ struct TM_TriMesh *bm,
+ bool smooth_shading,
+ struct TriMeshLog *log,
+ const int cd_vert_node_offset,
+ const int cd_face_node_offset);
+
+void BKE_pbvh_free(PBVH *bvh);
+// void BKE_pbvh_free_layer_disp(PBVH *bvh);
/* Hierarchical Search in the BVH, two methods:
* - for each hit calling a callback
@@ -161,7 +274,7 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh,
const float ray_normal[3],
struct IsectRayPrecalc *isect_precalc,
float *depth,
- int *active_vertex_index,
+ SculptIdx *active_vertex_index,
int *active_face_grid_index,
float *face_normal);
@@ -170,6 +283,11 @@ bool BKE_pbvh_bmesh_node_raycast_detail(PBVHNode *node,
struct IsectRayPrecalc *isect_precalc,
float *depth,
float *r_edge_length);
+bool BKE_pbvh_trimesh_node_raycast_detail(PBVHNode *node,
+ const float ray_start[3],
+ struct IsectRayPrecalc *isect_precalc,
+ float *depth,
+ float *r_edge_length);
/* for orthographic cameras, project the far away ray segment points to the root node so
* we can have better precision. */
@@ -207,11 +325,7 @@ void BKE_pbvh_draw_debug_cb(
void *user_data);
/* PBVH Access */
-typedef enum {
- PBVH_FACES,
- PBVH_GRIDS,
- PBVH_BMESH,
-} PBVHType;
+typedef enum { PBVH_FACES, PBVH_GRIDS, PBVH_BMESH, PBVH_TRIMESH } PBVHType;
PBVHType BKE_pbvh_type(const PBVH *pbvh);
bool BKE_pbvh_has_faces(const PBVH *pbvh);
@@ -238,6 +352,8 @@ int BKE_pbvh_get_grid_num_vertices(const PBVH *pbvh);
/* Only valid for type == PBVH_BMESH */
struct BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh);
+struct TM_TriMesh *BKE_pbvh_get_trimesh(PBVH *pbvh);
+void BKE_pbvh_topology_detail_size_set(PBVH *pbvh, float detail_size);
void BKE_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size);
typedef enum {
@@ -252,6 +368,14 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
const bool use_frontface,
const bool use_projected);
+bool BKE_pbvh_trimesh_update_topology(PBVH *bvh,
+ PBVHTopologyUpdateMode mode,
+ const float center[3],
+ const float view_normal[3],
+ float radius,
+ const bool use_frontface,
+ const bool use_projected,
+ int sym_axis);
/* Node Access */
void BKE_pbvh_node_mark_update(PBVHNode *node);
@@ -298,6 +422,12 @@ struct GSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node);
void BKE_pbvh_bmesh_node_save_orig(struct BMesh *bm, PBVHNode *node);
void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh);
+struct TMElemSet *BKE_pbvh_trimesh_node_unique_verts(PBVHNode *node);
+struct TMElemSet *BKE_pbvh_trimesh_node_other_verts(PBVHNode *node);
+struct GSet *BKE_pbvh_trimesh_node_faces(PBVHNode *node);
+void BKE_pbvh_trimesh_node_save_orig(struct TM_TriMesh *tm, PBVHNode *node);
+void BKE_pbvh_trimesh_after_stroke(PBVH *bvh);
+
/* Update Bounding Box/Redraw and clear flags */
void BKE_pbvh_update_bounds(PBVH *pbvh, int flags);
@@ -334,6 +464,8 @@ bool BKE_pbvh_is_deformed(struct PBVH *pbvh);
#define PBVH_ITER_ALL 0
#define PBVH_ITER_UNIQUE 1
+struct TMVert;
+
typedef struct PBVHVertexIter {
/* iteration */
int g;
@@ -342,7 +474,7 @@ typedef struct PBVHVertexIter {
int gx;
int gy;
int i;
- int index;
+ SculptIdx index;
bool respect_hide;
/* grid */
@@ -365,12 +497,20 @@ typedef struct PBVHVertexIter {
struct GSetIterator bm_unique_verts;
struct GSetIterator bm_other_verts;
struct CustomData *bm_vdata;
+
+ int ti;
+ struct TMElemSet *tm_cur_set;
+ struct TMElemSet *tm_unique_verts;
+ struct TMElemSet *tm_other_verts;
+ struct CustomData *tm_vdata;
+
int cd_vert_mask_offset;
/* result: these are all computed in the macro, but we assume
* that compiler optimization's will skip the ones we don't use */
struct MVert *mvert;
struct BMVert *bm_vert;
+ struct TMVert *tm_vert;
float *co;
short *no;
float *fno;
@@ -435,6 +575,42 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
vi.col = vi.vcol[vi.index].color; \
} \
} \
+ else if (vi.tm_vdata) { \
+ TMVert *tv = NULL; \
+ while (!tv) { \
+ if (!vi.tm_cur_set->elems || vi.ti >= vi.tm_cur_set->cur) { \
+ if (vi.tm_cur_set != vi.tm_other_verts) { \
+ vi.tm_cur_set = vi.tm_other_verts; \
+ vi.ti = 0; \
+ if (!vi.tm_cur_set->elems || vi.ti >= vi.tm_other_verts->cur) { \
+ break; \
+ } \
+ } \
+ else { \
+ break; \
+ } \
+ } \
+ else { \
+ tv = vi.tm_cur_set->elems[vi.ti++]; \
+ if (tv && BLI_safepool_elem_is_dead(tv)) { \
+ printf("dead vert: %p\n", tv); \
+ tv = NULL; \
+ } \
+ } \
+ } \
+ if (!tv) { \
+ continue; \
+ } \
+ vi.tm_vert = tv; \
+ vi.visible = !TM_elem_flag_test_bool(vi.tm_vert, TM_ELEM_HIDDEN); \
+ if (mode == PBVH_ITER_UNIQUE && !vi.visible) { \
+ continue; \
+ } \
+ vi.co = vi.tm_vert->co; \
+ vi.fno = vi.tm_vert->no; \
+ vi.index = (SculptIdx)vi.tm_vert; \
+ vi.mask = TM_ELEM_CD_GET_VOID_P(vi.tm_vert, vi.cd_vert_mask_offset); \
+ } \
else { \
if (!BLI_gsetIterator_done(&vi.bm_unique_verts)) { \
vi.bm_vert = BLI_gsetIterator_getKey(&vi.bm_unique_verts); \
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 0fbc8c4c229..74eeb4405f7 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -25,6 +25,7 @@ set(INC
../blenloader
../blentranslation
../bmesh
+ ../trimesh
../depsgraph
../draw
../functions
@@ -207,6 +208,7 @@ set(SRC
intern/particle_distribute.c
intern/particle_system.c
intern/pbvh.c
+ intern/pbvh_trimesh.c
intern/pbvh_bmesh.c
intern/pointcache.c
intern/pointcloud.c
@@ -422,6 +424,7 @@ set(LIB
bf_blenloader
bf_blentranslation
bf_bmesh
+ bf_trimesh
bf_depsgraph
bf_draw
bf_functions
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c
index d63c5fe12ab..0b8f87f47d3 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf.c
@@ -1039,6 +1039,7 @@ CCGError ccgSubSurf_updateToFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF,
* and vertices, for multires displacements */
CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
{
+ return eCCGError_None;
CCGVert **effectedV;
CCGEdge **effectedE;
int numEffectedV, numEffectedE, freeF;
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index d551eaf04e4..082438f9317 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -86,7 +86,7 @@
# define ASSERT_IS_VALID_MESH(mesh)
#endif
-static ThreadRWMutex loops_cache_lock = PTHREAD_RWLOCK_INITIALIZER;
+static ThreadRWMutex loops_cache_lock = BLI_RWLOCK_INITIALIZER;
static void mesh_init_origspace(Mesh *mesh);
static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
@@ -912,7 +912,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
const bool has_multires = BKE_sculpt_multires_active(scene, ob) != NULL;
bool multires_applied = false;
const bool sculpt_mode = ob->mode & OB_MODE_SCULPT && ob->sculpt && !use_render;
- const bool sculpt_dyntopo = (sculpt_mode && ob->sculpt->bm) && !use_render;
+ const bool sculpt_dyntopo = (sculpt_mode && (ob->sculpt->bm || ob->sculpt->tm)) && !use_render;
/* Modifier evaluation contexts for different types of modifiers. */
ModifierApplyFlag apply_render = use_render ? MOD_APPLY_RENDER : 0;
diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c
index a85509b11db..4d7ebba7064 100644
--- a/source/blender/blenkernel/intern/anim_data.c
+++ b/source/blender/blenkernel/intern/anim_data.c
@@ -422,7 +422,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/collection.c b/source/blender/blenkernel/intern/collection.c
index 0ed6f94ce79..3c86f0973dd 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -479,8 +479,8 @@ 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)
+ uint duplicate_flags,
+ uint duplicate_options)
{
const bool is_subprocess = (duplicate_options & LIB_ID_DUPLICATE_IS_SUBPROCESS) != 0;
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 2b2b1fb70ce..60d88f918d3 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -39,6 +39,7 @@
#include "BLI_math.h"
#include "BLI_math_color_blend.h"
#include "BLI_mempool.h"
+#include "BLI_threadsafe_mempool.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "BLI_string_utils.h"
@@ -58,6 +59,7 @@
#include "BLO_read_write.h"
#include "bmesh.h"
+#include "trimesh.h"
#include "CLG_log.h"
@@ -3454,25 +3456,25 @@ void CustomData_bmesh_do_versions_update_active_layers(CustomData *fdata, Custom
}
}
-void CustomData_bmesh_init_pool(CustomData *data, int totelem, const char htype)
+void CustomData_trimesh_init_pool(TM_TriMesh *tm, CustomData *data, int totelem, const char htype)
{
int chunksize;
/* Dispose old pools before calling here to avoid leaks */
- BLI_assert(data->pool == NULL);
+ BLI_assert(data->tpool == NULL);
switch (htype) {
- case BM_VERT:
- chunksize = bm_mesh_chunksize_default.totvert;
+ case TM_VERTEX:
+ chunksize = 512;
break;
- case BM_EDGE:
- chunksize = bm_mesh_chunksize_default.totedge;
+ case TM_EDGE:
+ chunksize = 1024;
break;
- case BM_LOOP:
- chunksize = bm_mesh_chunksize_default.totloop;
+ case TM_LOOP:
+ chunksize = 2048;
break;
- case BM_FACE:
- chunksize = bm_mesh_chunksize_default.totface;
+ case TM_TRI:
+ chunksize = 512;
break;
default:
BLI_assert(0);
@@ -3482,8 +3484,135 @@ void CustomData_bmesh_init_pool(CustomData *data, int totelem, const char htype)
/* If there are no layers, no pool is needed just yet */
if (data->totlayer) {
- data->pool = BLI_mempool_create(data->totsize, totelem, chunksize, BLI_MEMPOOL_NOP);
+ data->tpool = BLI_safepool_create(data->totsize, chunksize, tm->maxthread);
+ }
+}
+
+//XXX original code got axed in. . .copy/paste error? anyway, restore it from GIT later
+void CustomData_bmesh_init_pool(CustomData *data, int totelem, const char htype)
+{
+ int chunksize;
+
+ /* Dispose old pools before calling here to avoid leaks */
+ BLI_assert(data->tpool == NULL);
+
+ switch (htype) {
+ case BM_VERT:
+ chunksize = 512;
+ break;
+ case BM_EDGE:
+ chunksize = 1024;
+ break;
+ case BM_LOOP:
+ chunksize = 2048;
+ break;
+ case BM_FACE:
+ chunksize = 512;
+ break;
+ default:
+ BLI_assert(0);
+ chunksize = 512;
+ break;
+ }
+
+ /* If there are no layers, no pool is needed just yet */
+ if (data->totlayer) {
+ data->tpool = BLI_safepool_create(data->totsize, chunksize, 1);
+ }
+}
+
+bool CustomData_trimesh_merge(const CustomData *source,
+ CustomData *dest,
+ CustomDataMask mask,
+ eCDAllocType alloctype,
+ TM_TriMesh *bm,
+ const char htype)
+{
+ TMElement *h;
+ TM_TriMeshIter iter;
+ CustomData destold;
+ void *tmp;
+ int iter_type;
+ int totelem;
+
+ if (CustomData_number_of_layers_typemask(source, mask) == 0) {
+ return false;
}
+
+ /* copy old layer description so that old data can be copied into
+ * the new allocation */
+ destold = *dest;
+ if (destold.layers) {
+ destold.layers = MEM_dupallocN(destold.layers);
+ }
+
+ if (CustomData_merge(source, dest, mask, alloctype, 0) == false) {
+ if (destold.layers) {
+ MEM_freeN(destold.layers);
+ }
+ return false;
+ }
+
+ switch (htype) {
+ case TM_VERTEX:
+ iter_type = TM_VERTS_OF_MESH;
+ totelem = bm->totvert;
+ break;
+ case TM_EDGE:
+ iter_type = TM_EDGES_OF_MESH;
+ totelem = bm->totedge;
+ break;
+ case BM_LOOP:
+ iter_type = -1;
+ totelem = bm->tottri*3;
+ break;
+ case BM_FACE:
+ iter_type = TM_TRIS_OF_MESH;
+ totelem = bm->tottri;
+ break;
+ default: /* should never happen */
+ BLI_assert(!"invalid type given");
+ iter_type = TM_VERTS_OF_MESH;
+ totelem = bm->totvert;
+ break;
+ }
+
+ dest->tpool = NULL;
+ CustomData_trimesh_init_pool(bm, dest, totelem, htype);
+
+ if (iter_type != -1) {
+ /*ensure all current elements follow new customdata layout*/
+
+ TM_ITER_MESH (h, &iter, bm, iter_type) {
+ tmp = NULL;
+ CustomData_bmesh_copy_data(&destold, dest, h->customdata, &tmp);
+ CustomData_bmesh_free_block(&destold, &h->customdata);
+ h->customdata = tmp;
+ }
+ }
+ else {
+ TMFace *f;
+
+ /*ensure all current elements follow new customdata layout*/
+ TM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ for (int i=0; i<3; i++) {
+ TMLoopData *l = TM_GET_TRI_LOOP(f, i);
+
+ tmp = NULL;
+ CustomData_bmesh_copy_data(&destold, dest, l->customdata, &tmp);
+ CustomData_bmesh_free_block(&destold, &l->customdata);
+ l->customdata = tmp;
+ }
+ }
+ }
+
+ if (destold.tpool) {
+ BLI_safepool_destroy(destold.tpool);
+ }
+ if (destold.layers) {
+ MEM_freeN(destold.layers);
+ }
+ return true;
}
bool CustomData_bmesh_merge(const CustomData *source,
@@ -3538,7 +3667,7 @@ bool CustomData_bmesh_merge(const CustomData *source,
break;
}
- dest->pool = NULL;
+ dest->tpool = NULL;
CustomData_bmesh_init_pool(dest, totelem, htype);
if (iter_type != BM_LOOPS_OF_FACE) {
@@ -3569,8 +3698,8 @@ bool CustomData_bmesh_merge(const CustomData *source,
}
}
- if (destold.pool) {
- BLI_mempool_destroy(destold.pool);
+ if (destold.tpool) {
+ BLI_safepool_destroy(destold.tpool);
}
if (destold.layers) {
MEM_freeN(destold.layers);
@@ -3596,7 +3725,7 @@ void CustomData_bmesh_free_block(CustomData *data, void **block)
}
if (data->totsize) {
- BLI_mempool_free(data->pool, *block);
+ BLI_safepool_free(data->tpool, *block);
}
*block = NULL;
@@ -3631,7 +3760,7 @@ static void CustomData_bmesh_alloc_block(CustomData *data, void **block)
}
if (data->totsize > 0) {
- *block = BLI_mempool_alloc(data->pool);
+ *block = BLI_safepool_alloc(data->tpool);
}
else {
*block = NULL;
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index cfe81531204..2b8afae2b29 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -623,7 +623,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_validate.cc b/source/blender/blenkernel/intern/mesh_validate.cc
index 16733729be0..aeefa9db489 100644
--- a/source/blender/blenkernel/intern/mesh_validate.cc
+++ b/source/blender/blenkernel/intern/mesh_validate.cc
@@ -18,6 +18,8 @@
* \ingroup bke
*/
+#define NOMINMAX
+
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
@@ -87,25 +89,50 @@ static void reserve_hash_maps(const Mesh *mesh,
MutableSpan<EdgeMap> edge_maps)
{
const int totedge_guess = std::max(keep_existing_edges ? mesh->totedge : 0, mesh->totpoly * 2);
- parallel_for_each(
- edge_maps, [&](EdgeMap &edge_map) { edge_map.reserve(totedge_guess / edge_maps.size()); });
+
+#ifndef __clang__
+ parallel_for_each(edge_maps,
+ [&](EdgeMap &edge_map) {
+#else
+ int ilen = edge_maps.size();
+
+ for (int i = 0; i < ilen; i++) {
+ EdgeMap &edge_map = edge_maps[i];
+#endif
+ edge_map.reserve(totedge_guess / edge_maps.size());
+ }
+#ifndef __clang__
+ );
+#endif
}
static void add_existing_edges_to_hash_maps(Mesh *mesh,
MutableSpan<EdgeMap> edge_maps,
uint32_t parallel_mask)
{
+#ifndef __clang__
/* Assume existing edges are valid. */
- parallel_for_each(edge_maps, [&](EdgeMap &edge_map) {
- const int task_index = &edge_map - &edge_maps[0];
- for (const MEdge &edge : Span(mesh->medge, mesh->totedge)) {
- OrderedEdge ordered_edge{edge.v1, edge.v2};
- /* Only add the edge when it belongs into this map. */
- if (task_index == (parallel_mask & ordered_edge.hash2())) {
- edge_map.add_new(ordered_edge, {&edge});
- }
- }
- });
+ parallel_for_each(edge_maps,
+ [&](EdgeMap &edge_map) {
+#else
+ int ilen = edge_maps.size();
+
+ for (int i = 0; i < ilen; i++) {
+ EdgeMap &edge_map = edge_maps[i];
+#endif
+ const int task_index = &edge_map - &edge_maps[0];
+ for (const MEdge &edge : Span(mesh->medge, mesh->totedge)) {
+ OrderedEdge ordered_edge{edge.v1, edge.v2};
+ /* Only add the edge when it belongs into this map. */
+ if (task_index == (parallel_mask & ordered_edge.hash2())) {
+ edge_map.add_new(ordered_edge, {&edge});
+ }
+ }
+ }
+
+#ifndef __clang__
+ );
+#endif
}
static void add_polygon_edges_to_hash_maps(Mesh *mesh,
@@ -113,24 +140,36 @@ static void add_polygon_edges_to_hash_maps(Mesh *mesh,
uint32_t parallel_mask)
{
const Span<MLoop> loops{mesh->mloop, mesh->totloop};
- parallel_for_each(edge_maps, [&](EdgeMap &edge_map) {
- const int task_index = &edge_map - &edge_maps[0];
- for (const MPoly &poly : Span(mesh->mpoly, mesh->totpoly)) {
- Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
- const MLoop *prev_loop = &poly_loops.last();
- for (const MLoop &next_loop : poly_loops) {
- /* Can only be the same when the mesh data is invalid. */
- if (prev_loop->v != next_loop.v) {
- OrderedEdge ordered_edge{prev_loop->v, next_loop.v};
- /* Only add the edge when it belongs into this map. */
- if (task_index == (parallel_mask & ordered_edge.hash2())) {
- edge_map.lookup_or_add(ordered_edge, {nullptr});
- }
- }
- prev_loop = &next_loop;
- }
- }
- });
+#ifndef __clang__
+ parallel_for_each(edge_maps,
+ [&](EdgeMap &edge_map) {
+#else
+ int ilen = edge_maps.size();
+
+ for (int i = 0; i < ilen; i++) {
+ EdgeMap &edge_map = edge_maps[i];
+
+#endif
+ const int task_index = &edge_map - &edge_maps[0];
+ for (const MPoly &poly : Span(mesh->mpoly, mesh->totpoly)) {
+ Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
+ const MLoop *prev_loop = &poly_loops.last();
+ for (const MLoop &next_loop : poly_loops) {
+ /* Can only be the same when the mesh data is invalid. */
+ if (prev_loop->v != next_loop.v) {
+ OrderedEdge ordered_edge{prev_loop->v, next_loop.v};
+ /* Only add the edge when it belongs into this map. */
+ if (task_index == (parallel_mask & ordered_edge.hash2())) {
+ edge_map.lookup_or_add(ordered_edge, {nullptr});
+ }
+ }
+ prev_loop = &next_loop;
+ }
+ }
+ }
+#ifndef __clang__
+ );
+#endif
}
static void serialize_and_initialize_deduplicated_edges(MutableSpan<EdgeMap> edge_maps,
@@ -146,27 +185,38 @@ static void serialize_and_initialize_deduplicated_edges(MutableSpan<EdgeMap> edg
edge_index_offsets[i + 1] = edge_index_offsets[i] + edge_maps[i].size();
}
- parallel_for_each(edge_maps, [&](EdgeMap &edge_map) {
- const int task_index = &edge_map - &edge_maps[0];
-
- int new_edge_index = edge_index_offsets[task_index];
- for (EdgeMap::MutableItem item : edge_map.items()) {
- MEdge &new_edge = new_edges[new_edge_index];
- const MEdge *orig_edge = item.value.original_edge;
- if (orig_edge != nullptr) {
- /* Copy values from original edge. */
- new_edge = *orig_edge;
- }
- else {
- /* Initialize new edge. */
- new_edge.v1 = item.key.v_low;
- new_edge.v2 = item.key.v_high;
- new_edge.flag = new_edge_flag;
- }
- item.value.index = new_edge_index;
- new_edge_index++;
- }
- });
+#ifndef __clang__
+ parallel_for_each(edge_maps,
+ [&](EdgeMap &edge_map) {
+#else
+ int ilen = edge_maps.size();
+
+ for (int i = 0; i < ilen; i++) {
+ EdgeMap &edge_map = edge_maps[i];
+#endif
+ const int task_index = &edge_map - &edge_maps[0];
+
+ int new_edge_index = edge_index_offsets[task_index];
+ for (EdgeMap::MutableItem item : edge_map.items()) {
+ MEdge &new_edge = new_edges[new_edge_index];
+ const MEdge *orig_edge = item.value.original_edge;
+ if (orig_edge != nullptr) {
+ /* Copy values from original edge. */
+ new_edge = *orig_edge;
+ }
+ else {
+ /* Initialize new edge. */
+ new_edge.v1 = item.key.v_low;
+ new_edge.v2 = item.key.v_high;
+ new_edge.flag = new_edge_flag;
+ }
+ item.value.index = new_edge_index;
+ new_edge_index++;
+ }
+ }
+#ifndef __clang__
+ );
+#endif
}
static void update_edge_indices_in_poly_loops(Mesh *mesh,
@@ -174,31 +224,46 @@ static void update_edge_indices_in_poly_loops(Mesh *mesh,
uint32_t parallel_mask)
{
const MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
- parallel_for(IndexRange(mesh->totpoly), 100, [&](IndexRange range) {
- for (const int poly_index : range) {
- MPoly &poly = mesh->mpoly[poly_index];
- MutableSpan<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
-
- MLoop *prev_loop = &poly_loops.last();
- for (MLoop &next_loop : poly_loops) {
- int edge_index;
- if (prev_loop->v != next_loop.v) {
- OrderedEdge ordered_edge{prev_loop->v, next_loop.v};
- /* Double lookup: First find the map that contains the edge, then lookup the edge. */
- const EdgeMap &edge_map = edge_maps[parallel_mask & ordered_edge.hash2()];
- edge_index = edge_map.lookup(ordered_edge).index;
- }
- else {
- /* This is an invalid edge; normally this does not happen in Blender,
- * but it can be part of an imported mesh with invalid geometry. See
- * T76514. */
- edge_index = 0;
- }
- prev_loop->e = edge_index;
- prev_loop = &next_loop;
- }
- }
- });
+#ifndef __clang__
+ parallel_for(IndexRange(mesh->totpoly),
+ 100,
+ [&](IndexRange range) {
+#else
+ int ilen = edge_maps.size();
+
+ for (int i = 0; i < ilen; i++) {
+ const EdgeMap &edge_map = edge_maps[i];
+ IndexRange range(i);
+
+#endif
+ for (const int poly_index : range) {
+ MPoly &poly = mesh->mpoly[poly_index];
+ MutableSpan<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
+
+ MLoop *prev_loop = &poly_loops.last();
+ for (MLoop &next_loop : poly_loops) {
+ int edge_index;
+ if (prev_loop->v != next_loop.v) {
+ OrderedEdge ordered_edge{prev_loop->v, next_loop.v};
+ /* Double lookup: First find the map that contains the edge, then lookup the
+ * edge. */
+ const EdgeMap &edge_map = edge_maps[parallel_mask & ordered_edge.hash2()];
+ edge_index = edge_map.lookup(ordered_edge).index;
+ }
+ else {
+ /* This is an invalid edge; normally this does not happen in Blender,
+ * but it can be part of an imported mesh with invalid geometry. See
+ * T76514. */
+ edge_index = 0;
+ }
+ prev_loop->e = edge_index;
+ prev_loop = &next_loop;
+ }
+ }
+ }
+#ifndef __clang__
+ );
+#endif
}
static int get_parallel_maps_count(const Mesh *mesh)
@@ -215,7 +280,20 @@ static int get_parallel_maps_count(const Mesh *mesh)
static void clear_hash_tables(MutableSpan<EdgeMap> edge_maps)
{
- parallel_for_each(edge_maps, [](EdgeMap &edge_map) { edge_map.clear(); });
+#ifndef __clang__
+ parallel_for_each(edge_maps,
+ [](EdgeMap &edge_map) {
+#else
+ int ilen = edge_maps.size();
+
+ for (int i = 0; i < ilen; i++) {
+ EdgeMap &edge_map = edge_maps[i];
+#endif
+ edge_map.clear();
+ }
+#ifndef __clang__
+ );
+#endif
}
} // namespace blender::bke::calc_edges
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index a8017569ba9..6f537cf00a4 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -1799,8 +1799,8 @@ void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src)
*/
Object *BKE_object_duplicate(Main *bmain,
Object *ob,
- eDupli_ID_Flags dupflag,
- const eLibIDDuplicateFlags duplicate_options)
+ uint dupflag,
+ const uint duplicate_options)
{
const bool is_subprocess = (duplicate_options & LIB_ID_DUPLICATE_IS_SUBPROCESS) != 0;
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 88415140a5b..d940ad5cf9d 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -76,6 +76,7 @@
#include "BLO_read_write.h"
#include "bmesh.h"
+#include "trimesh.h"
static void palette_init_data(ID *id)
{
@@ -1083,7 +1084,9 @@ bool BKE_paint_ensure(ToolSettings *ts, struct Paint **r_paint)
paint = &ts->imapaint.paint;
}
- paint->flags |= PAINT_SHOW_BRUSH;
+ if (paint) {
+ paint->flags |= PAINT_SHOW_BRUSH;
+ }
*r_paint = paint;
@@ -1199,6 +1202,17 @@ bool paint_is_bmesh_face_hidden(BMFace *f)
return false;
}
+
+/* Return true if all vertices in the face are visible, false otherwise */
+bool paint_is_trimesh_face_hidden(TMFace *f)
+{
+ bool ret = f->v1->flag & TM_ELEM_HIDDEN;
+ ret = ret || (f->v2->flag & TM_ELEM_HIDDEN);
+ ret = ret || (f->v3->flag & TM_ELEM_HIDDEN);
+
+ return ret;
+}
+
float paint_grid_paint_mask(const GridPaintMask *gpm, uint level, uint x, uint y)
{
int factor = BKE_ccg_factor(level, gpm->level);
@@ -1298,6 +1312,34 @@ void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss)
MEM_SAFE_FREE(gmap->poly_map_mem);
}
+/* Write out the sculpt dynamic-topology BMesh to the Mesh */
+static void sculptsession_tm_to_me_update_data_only(Object *ob, bool reorder)
+{
+ SculptSession *ss = ob->sculpt;
+
+ if (ss->tm) {
+ if (ob->data) {
+ TM_TriMeshIter iter;
+ TMFace *f;
+
+ TM_tri_iternew(ss->tm, &iter);
+ f = TM_iterstep(&iter);
+ for (; f; f = TM_iterstep(&iter)) {
+ TM_elem_flag_set(f, TRIMESH_SMOOTH, ss->bm_smooth_shading);
+ }
+ //if (reorder) {
+ // BM_log_mesh_elems_reorder(ss->tm, ss->tm_log);
+ //}
+ TM_mesh_bm_to_me(NULL,
+ ss->tm,
+ ob->data,
+ (&(struct TMeshToMeshParams){
+ .calc_object_remap = false,
+ }));
+ }
+ }
+}
+
/**
* Write out the sculpt dynamic-topology #BMesh to the #Mesh.
*/
@@ -1336,6 +1378,17 @@ void BKE_sculptsession_bm_to_me(Object *ob, bool reorder)
}
}
+void BKE_sculptsession_tm_to_me(Object *ob, bool reorder)
+{
+ if (ob && ob->sculpt) {
+ sculptsession_tm_to_me_update_data_only(ob, reorder);
+
+ /* Ensure the objects evaluated mesh doesn't hold onto arrays
+ * now realloc'd in the mesh T34473. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+}
+
static void sculptsession_free_pbvh(Object *object)
{
SculptSession *ss = object->sculpt;
@@ -1387,14 +1440,36 @@ void BKE_sculptsession_bm_to_me_for_render(Object *object)
}
}
+void BKE_sculptsession_tm_to_me_for_render(Object *object)
+{
+ if (object && object->sculpt) {
+ if (object->sculpt->tm) {
+ /* Ensure no points to old arrays are stored in DM
+ *
+ * Apparently, we could not use DEG_id_tag_update
+ * here because this will lead to the while object
+ * surface to disappear, so we'll release DM in place.
+ */
+ BKE_object_free_derived_caches(object);
+
+ sculptsession_tm_to_me_update_data_only(object, false);
+
+ /* In contrast with sculptsession_bm_to_me no need in
+ * DAG tag update here - derived mesh was freed and
+ * old pointers are nowhere stored.
+ */
+ }
+ }
+}
+
void BKE_sculptsession_free(Object *ob)
{
if (ob && ob->sculpt) {
SculptSession *ss = ob->sculpt;
- if (ss->bm) {
- BKE_sculptsession_bm_to_me(ob, true);
- BM_mesh_free(ss->bm);
+ if (ss->tm) {
+ BKE_sculptsession_tm_to_me(ob, true);
+ TMesh_free(ss->tm);
}
sculptsession_free_pbvh(ob);
@@ -1439,7 +1514,7 @@ MultiresModifierData *BKE_sculpt_multires_active(Scene *scene, Object *ob)
ModifierData *md;
VirtualModifierData virtualModifierData;
- if (ob->sculpt && ob->sculpt->bm) {
+ if (ob->sculpt && (ob->sculpt->bm || ob->sculpt->tm)) {
/* can't combine multires and dynamic topology */
return NULL;
}
@@ -1481,7 +1556,7 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
Mesh *me = (Mesh *)ob->data;
VirtualModifierData virtualModifierData;
- if (ob->sculpt->bm || BKE_sculpt_multires_active(scene, ob)) {
+ if (BKE_sculpt_multires_active(scene, ob) || ob->sculpt->bm || ob->sculpt->tm) {
return false;
}
@@ -1969,10 +2044,10 @@ void BKE_sculpt_sync_face_set_visibility(struct Mesh *mesh, struct SubdivCCG *su
static PBVH *build_pbvh_for_dynamic_topology(Object *ob)
{
PBVH *pbvh = BKE_pbvh_new();
- BKE_pbvh_build_bmesh(pbvh,
- ob->sculpt->bm,
+ BKE_pbvh_build_trimesh(pbvh,
+ ob->sculpt->tm,
ob->sculpt->bm_smooth_shading,
- ob->sculpt->bm_log,
+ ob->sculpt->tm_log,
ob->sculpt->cd_vert_node_offset,
ob->sculpt->cd_face_node_offset);
pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
@@ -2069,8 +2144,8 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
return pbvh;
}
- if (ob->sculpt->bm != NULL) {
- /* Sculpting on a BMesh (dynamic-topology) gets a special PBVH. */
+ if (ob->sculpt->tm != NULL) {
+ /* Sculpting on a TriMesh (dynamic-topology) gets a special PBVH. */
pbvh = build_pbvh_for_dynamic_topology(ob);
}
else {
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 1e4ea19adb6..f718904963e 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -42,6 +42,7 @@
#include "GPU_buffers.h"
#include "bmesh.h"
+#include "trimesh.h"
#include "atomic_ops.h"
@@ -49,7 +50,7 @@
#include <limits.h>
-#define LEAF_LIMIT 10000
+#define LEAF_LIMIT 600
//#define PERFCNTRS
@@ -595,6 +596,16 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
BB_reset(&cb);
+ for (int i = 0; i < totvert; i++) {
+ MVert *mv = verts + i;
+
+ for (int j = 0; j < 3; j++) {
+ if (isnan(mv->co[j])) {
+ mv->co[j] = 0.0f;
+ }
+ }
+ }
+
/* For each face, store the AABB and the AABB centroid */
prim_bbc = MEM_mallocN(sizeof(BBC) * looptri_num, "prim_bbc");
@@ -692,6 +703,27 @@ void BKE_pbvh_free(PBVH *pbvh)
if (node->face_vert_indices) {
MEM_freeN((void *)node->face_vert_indices);
}
+
+ if (node->tm_orco) {
+ MEM_freeN(node->tm_orco);
+ }
+
+ if (node->tm_ortri) {
+ MEM_freeN(node->tm_ortri);
+ }
+
+ if (node->tm_unique_verts) {
+ TMElemSet_free(node->tm_unique_verts);
+ }
+
+ if (node->tm_other_verts) {
+ TMElemSet_free(node->tm_other_verts);
+ }
+
+ if (node->tm_faces) {
+ BLI_gset_free(node->tm_faces, NULL);
+ }
+
if (node->bm_faces) {
BLI_gset_free(node->bm_faces, NULL);
}
@@ -1292,6 +1324,10 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
node->draw_buffers = GPU_pbvh_bmesh_buffers_build(pbvh->flags &
PBVH_DYNTOPO_SMOOTH_SHADING);
break;
+ case PBVH_TRIMESH:
+ node->draw_buffers = GPU_pbvh_trimesh_buffers_build(pbvh->flags &
+ PBVH_DYNTOPO_SMOOTH_SHADING);
+ break;
}
}
@@ -1330,16 +1366,32 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
node->bm_other_verts,
update_flags);
break;
+ case PBVH_TRIMESH:
+ GPU_pbvh_trimesh_buffers_update(node->draw_buffers,
+ pbvh->tm,
+ node->tm_faces,
+ node->tm_unique_verts,
+ node->tm_other_verts,
+ update_flags,
+ pbvh->cd_vert_node_offset);
+ break;
}
}
}
static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode, int update_flag)
{
- if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(pbvh->type, PBVH_GRIDS, PBVH_BMESH)) {
+ if ((update_flag & PBVH_RebuildDrawBuffers) ||
+ ELEM(pbvh->type, PBVH_GRIDS, PBVH_TRIMESH, 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_Delete) {
+ printf("corrupted node! %p\n", node);
+ return;
+ }
+
if (node->flag & PBVH_RebuildDrawBuffers) {
GPU_pbvh_buffers_free(node->draw_buffers);
node->draw_buffers = NULL;
@@ -1352,6 +1404,9 @@ static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode,
else if (pbvh->type == PBVH_BMESH) {
GPU_pbvh_bmesh_buffers_update_free(node->draw_buffers);
}
+ else if (pbvh->type == PBVH_TRIMESH) {
+ GPU_pbvh_trimesh_buffers_update_free(node->draw_buffers);
+ }
}
}
}
@@ -1527,6 +1582,33 @@ static void pbvh_bmesh_node_visibility_update(PBVHNode *node)
BKE_pbvh_node_fully_hidden_set(node, true);
}
+static void pbvh_trimesh_node_visibility_update(PBVHNode *node)
+{
+ TMElemSet *unique, *other;
+ TMVert *v;
+
+ unique = BKE_pbvh_trimesh_node_unique_verts(node);
+ other = BKE_pbvh_trimesh_node_other_verts(node);
+
+ TMS_ITER (v, unique) {
+ if (!TM_elem_flag_test(v, TM_ELEM_HIDDEN)) {
+ BKE_pbvh_node_fully_hidden_set(node, false);
+ return;
+ }
+ }
+ TMS_ITER_END
+
+ TMS_ITER (v, other) {
+ if (!TM_elem_flag_test(v, TM_ELEM_HIDDEN)) {
+ BKE_pbvh_node_fully_hidden_set(node, false);
+ return;
+ }
+ }
+ TMS_ITER_END;
+
+ BKE_pbvh_node_fully_hidden_set(node, true);
+}
+
static void pbvh_update_visibility_task_cb(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict UNUSED(tls))
@@ -1546,6 +1628,9 @@ static void pbvh_update_visibility_task_cb(void *__restrict userdata,
case PBVH_BMESH:
pbvh_bmesh_node_visibility_update(node);
break;
+ case PBVH_TRIMESH:
+ pbvh_trimesh_node_visibility_update(node);
+ break;
}
node->flag &= ~PBVH_UpdateVisibility;
}
@@ -1660,6 +1745,9 @@ bool BKE_pbvh_has_faces(const PBVH *pbvh)
if (pbvh->type == PBVH_BMESH) {
return (pbvh->bm->totface != 0);
}
+ else if (pbvh->type == PBVH_TRIMESH) {
+ return pbvh->tm->tottri > 0;
+ }
return (pbvh->totprim != 0);
}
@@ -1713,6 +1801,12 @@ BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh)
return pbvh->bm;
}
+TM_TriMesh *BKE_pbvh_get_trimesh(PBVH *bvh)
+{
+ BLI_assert(bvh->type == PBVH_TRIMESH);
+ return bvh->tm;
+}
+
/***************************** Node Access ***********************************/
void BKE_pbvh_node_mark_update(PBVHNode *node)
@@ -1848,6 +1942,15 @@ void BKE_pbvh_node_num_verts(PBVH *pbvh, PBVHNode *node, int *r_uniquevert, int
*r_uniquevert = tot;
}
break;
+ case PBVH_TRIMESH:
+ tot = node->tm_unique_verts->length;
+ if (r_totvert) {
+ *r_totvert = tot + node->tm_other_verts->length;
+ }
+ if (r_uniquevert) {
+ *r_uniquevert = tot;
+ }
+ break;
}
}
@@ -1895,6 +1998,23 @@ void BKE_pbvh_node_get_grids(PBVH *pbvh,
*r_griddata = NULL;
}
break;
+ case PBVH_TRIMESH:
+ if (r_grid_indices) {
+ *r_grid_indices = NULL;
+ }
+ if (r_totgrid) {
+ *r_totgrid = 0;
+ }
+ if (r_maxgrid) {
+ *r_maxgrid = 0;
+ }
+ if (r_gridsize) {
+ *r_gridsize = 0;
+ }
+ if (r_griddata) {
+ *r_griddata = NULL;
+ }
+ break;
}
}
@@ -2122,7 +2242,7 @@ static bool pbvh_faces_node_raycast(PBVH *pbvh,
const float ray_normal[3],
struct IsectRayPrecalc *isect_precalc,
float *depth,
- int *r_active_vertex_index,
+ SculptIdx *r_active_vertex_index,
int *r_active_face_index,
float *r_face_normal)
{
@@ -2190,7 +2310,7 @@ static bool pbvh_grids_node_raycast(PBVH *pbvh,
const float ray_normal[3],
struct IsectRayPrecalc *isect_precalc,
float *depth,
- int *r_active_vertex_index,
+ SculptIdx *r_active_vertex_index,
int *r_active_grid_index,
float *r_face_normal)
{
@@ -2285,7 +2405,7 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh,
const float ray_normal[3],
struct IsectRayPrecalc *isect_precalc,
float *depth,
- int *active_vertex_index,
+ SculptIdx *active_vertex_index,
int *active_face_grid_index,
float *face_normal)
{
@@ -2331,6 +2451,17 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh,
active_vertex_index,
face_normal);
break;
+ case PBVH_TRIMESH:
+ // TM_mesh_elem_index_ensure(pbvh->tm, TM_VERTEX);
+ hit = pbvh_trimesh_node_raycast(node,
+ ray_start,
+ ray_normal,
+ isect_precalc,
+ depth,
+ use_origco,
+ active_vertex_index,
+ face_normal);
+ break;
}
return hit;
@@ -2565,6 +2696,10 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *pbvh,
hit = pbvh_bmesh_node_nearest_to_ray(
node, ray_start, ray_normal, depth, dist_sq, use_origco);
break;
+ case PBVH_TRIMESH:
+ hit = pbvh_trimesh_node_nearest_to_ray(
+ node, ray_start, ray_normal, depth, dist_sq, use_origco);
+ break;
}
return hit;
@@ -2646,6 +2781,9 @@ void BKE_pbvh_update_normals(PBVH *pbvh, struct SubdivCCG *subdiv_ccg)
if (pbvh->type == PBVH_BMESH) {
pbvh_bmesh_normals_update(nodes, totnode);
}
+ else if (pbvh->type == PBVH_TRIMESH) {
+ pbvh_trimesh_normals_update(nodes, totnode);
+ }
else if (pbvh->type == PBVH_FACES) {
pbvh_faces_update_normals(pbvh, nodes, totnode);
}
@@ -2726,7 +2864,7 @@ void BKE_pbvh_draw_cb(PBVH *pbvh,
for (int a = 0; a < totnode; a++) {
PBVHNode *node = nodes[a];
- if (node->flag & PBVH_UpdateDrawBuffers) {
+ if (node->flag & PBVH_UpdateDrawBuffers && node->draw_buffers) {
/* Flush buffers uses OpenGL, so not in parallel. */
GPU_pbvh_buffers_update_flush(node->draw_buffers);
}
@@ -2873,9 +3011,11 @@ void BKE_pbvh_node_free_proxies(PBVHNode *node)
node->proxies[p].co = NULL;
}
- MEM_freeN(node->proxies);
- node->proxies = NULL;
+ if (node->proxies) {
+ MEM_freeN(node->proxies);
+ }
+ node->proxies = NULL;
node->proxy_count = 0;
}
@@ -2887,6 +3027,7 @@ void BKE_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***r_array, int *r_tot)
for (int n = 0; n < pbvh->totnode; n++) {
PBVHNode *node = pbvh->nodes + n;
+
if (node->proxy_count > 0) {
if (tot == space) {
/* resize array if needed */
@@ -2973,6 +3114,16 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
vi->cd_vert_mask_offset = CustomData_get_offset(vi->bm_vdata, CD_PAINT_MASK);
}
+ if (pbvh->type == PBVH_TRIMESH) {
+ vi->ti = 0;
+ vi->tm_unique_verts = node->tm_unique_verts;
+ vi->tm_other_verts = node->tm_other_verts;
+ vi->tm_cur_set = vi->tm_unique_verts;
+
+ vi->tm_vdata = &pbvh->tm->vdata;
+ vi->cd_vert_mask_offset = CustomData_get_offset(vi->tm_vdata, CD_PAINT_MASK);
+ }
+
vi->gh = NULL;
if (vi->grids && mode == PBVH_ITER_UNIQUE) {
vi->grid_hidden = pbvh->grid_hidden;
@@ -2994,6 +3145,8 @@ bool pbvh_has_mask(PBVH *pbvh)
return (pbvh->vdata && CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK));
case PBVH_BMESH:
return (pbvh->bm && (CustomData_get_offset(&pbvh->bm->vdata, CD_PAINT_MASK) != -1));
+ case PBVH_TRIMESH:
+ return (pbvh->tm && (CustomData_get_offset(&pbvh->tm->vdata, CD_PAINT_MASK) != -1));
}
return false;
@@ -3006,6 +3159,8 @@ bool pbvh_has_face_sets(PBVH *pbvh)
return (pbvh->pdata && CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS));
case PBVH_FACES:
return (pbvh->pdata && CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS));
+ case PBVH_TRIMESH:
+ return false;
case PBVH_BMESH:
return false;
}
@@ -3067,3 +3222,387 @@ void BKE_pbvh_respect_hide_set(PBVH *pbvh, bool respect_hide)
{
pbvh->respect_hide = respect_hide;
}
+
+#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)
+{
+ if (!*data && (emask & umask)) {
+ *data = MEM_callocN(newsize * esize, "pbvh proxy vert arrays");
+ return emask;
+ }
+ // update channel if it already was allocated once, or is requested by umask
+ else if (newsize != oldsize && (*data || (emask & umask))) {
+ *data = MEM_reallocN(data, newsize * esize);
+ 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;
+
+ 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.index, (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;
+
+ BKE_pbvh_node_num_verts(pbvh, node, &totvert, NULL);
+
+ bool bad = p->size != totvert || !p->neighbors;
+ bad = bad || (p->datamask & mask) != mask;
+
+ bad = bad && totvert > 0;
+
+ return bad;
+}
+
+GHash *pbvh_build_vert_node_map(PBVH *pbvh, int mask)
+{
+ GHash *vert_node_map = BLI_ghash_ptr_new("BKE_pbvh_ensure_proxyarrays");
+
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHVertexIter vd;
+ PBVHNode *node = pbvh->nodes + i;
+
+ BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ BLI_ghash_insert(vert_node_map, (void *)vd.index, (void *)i);
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+
+ return vert_node_map;
+}
+
+void BKE_pbvh_ensure_proxyarrays(SculptSession *ss, PBVH *pbvh, int mask)
+{
+
+ bool update = false;
+
+ for (int i = 0; i < pbvh->totnode; i++) {
+ if (pbvh_proxyarray_needs_update(pbvh, pbvh->nodes + i, mask)) {
+ update = true;
+ break;
+ }
+ }
+
+ if (!update) {
+ return;
+ }
+
+ GHash *vert_node_map = pbvh_build_vert_node_map(pbvh, mask);
+
+ for (int i = 0; i < pbvh->totnode; i++) {
+ BKE_pbvh_ensure_proxyarray_indexmap(pbvh, pbvh->nodes + i, vert_node_map);
+ }
+
+ for (int i = 0; i < pbvh->totnode; i++) {
+ BKE_pbvh_ensure_proxyarray(ss, pbvh, 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(int))
+ UPDATETEST(neighbors, PV_NEIGHBORS, sizeof(ProxyKey) * MAX_PROXY_NEIGHBORS)
+
+ p->size = totvert;
+
+ if (force_update) {
+ updatemask |= mask;
+ }
+
+ if (!updatemask) {
+ return;
+ }
+
+ p->datamask |= mask;
+
+ PBVHVertexIter vd;
+
+ int i = 0;
+ BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ BLI_ghash_insert(gs, (void *)vd.index, (void *)i);
+ i++;
+ }
+ BKE_pbvh_vertex_iter_end;
+
+ i = 0;
+ BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ if (updatemask & PV_OWNERCO) {
+ p->ownerco[i] = vd.co;
+ }
+ if (updatemask & PV_INDEX) {
+ p->index[i] = vd.index;
+ }
+ if (updatemask & PV_OWNERNO) {
+ p->ownerno[i] = vd.no;
+ }
+ if (updatemask & PV_NO) {
+ if (vd.no) {
+ copy_v3_v3_short(p->no[i], vd.no);
+ normal_short_to_float_v3(p->fno[i], vd.no);
+ } else if (vd.fno) {
+ copy_v3_v3(p->fno[i], vd.fno);
+ normal_float_to_short_v3(p->no[i], p->fno[i]);
+ } else {
+ zero_v3(p->fno[i]);
+ p->fno[i][2] = 1.0f;
+ normal_float_to_short_v3(p->no[i], 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.index, ni) {
+ if (j >= MAX_PROXY_NEIGHBORS - 1) {
+ break;
+ }
+
+ ProxyKey key;
+
+ int *pindex = (int *)BLI_ghash_lookup_p(gs, (void *)ni.index);
+
+ if (!pindex) {
+ if (vert_node_map) {
+ int *nindex = BLI_ghash_lookup_p(vert_node_map, (void *)ni.index);
+
+ if (!nindex) {
+ continue;
+ }
+
+ PBVHNode *node2 = pbvh->nodes + *nindex;
+ if (node2->proxyverts.indexmap) {
+ pindex = (int *)BLI_ghash_lookup_p(node2->proxyverts.indexmap, (void *)ni.index);
+ }
+
+ if (!pindex) {
+ continue;
+ }
+
+ key.node = (int)(node2 - pbvh->nodes);
+ key.pindex = *pindex;
+ }
+ else {
+ 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 (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->co)
+ MEM_freeN(p->co);
+ if (p->no)
+ MEM_freeN(p->no);
+ if (p->index)
+ MEM_freeN(p->index);
+ if (p->mask)
+ MEM_freeN(p->mask);
+ if (p->ownerco)
+ MEM_freeN(p->ownerco);
+ if (p->ownerno)
+ MEM_freeN(p->ownerno);
+ if (p->ownermask)
+ MEM_freeN(p->ownermask);
+ if (p->ownercolor)
+ MEM_freeN(p->ownercolor);
+ if (p->color)
+ MEM_freeN(p->color);
+ if (p->neighbors)
+ MEM_freeN(p->neighbors);
+
+ memset(p, 0, sizeof(*p));
+}
+
+void BKE_pbvh_update_proxyvert(PBVH *pbvh, PBVHNode *node, ProxyVertUpdateRec *rec)
+{
+}
+
+ProxyVertArray *BKE_pbvh_get_proxyarrays(PBVH *pbvh, PBVHNode *node)
+{
+ return &node->proxyverts;
+}
+
+#endif
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index d31b0d54784..7c3b9edcc70 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -1512,7 +1512,7 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node,
struct IsectRayPrecalc *isect_precalc,
float *depth,
bool use_original,
- int *r_active_vertex_index,
+ SculptIdx *r_active_vertex_index,
float *r_face_normal)
{
bool hit = false;
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index 63bc8753fc7..0dfa8bd16e6 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -1,3 +1,6 @@
+#ifndef _PBVH_INTERN_H
+#define _PBVH_INTERN_H
+
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -30,6 +33,7 @@ typedef struct {
float bmin[3], bmax[3], bcentroid[3];
} BBC;
+struct GHash;
/* Note: this structure is getting large, might want to split it into
* union'd structs */
struct PBVHNode {
@@ -86,7 +90,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;
@@ -105,8 +109,24 @@ struct PBVHNode {
int (*bm_ortri)[3];
int bm_tot_ortri;
+ /* trimesh */
+ GSet *tm_faces;
+
+ TMElemSet *tm_unique_verts;
+ TMElemSet *tm_other_verts;
+ float (*tm_orco)[3];
+ int (*tm_ortri)[3];
+ int tm_tot_ortri;
+ int tm_tot_orco;
+
+ int tm_subtree_tottri;
+
/* 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 {
@@ -175,6 +195,14 @@ struct PBVH {
int num_planes;
struct BMLog *bm_log;
+
+ /* trimesh data */
+ struct TM_TriMesh *tm;
+ float tm_max_edge_len;
+ float tm_min_edge_len;
+
+ struct TriMeshLog *tm_log;
+
struct SubdivCCG *subdiv_ccg;
};
@@ -224,7 +252,7 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node,
struct IsectRayPrecalc *isect_precalc,
float *dist,
bool use_original,
- int *r_active_vertex_index,
+ SculptIdx *r_active_vertex_index,
float *r_face_normal);
bool pbvh_bmesh_node_nearest_to_ray(PBVHNode *node,
const float ray_start[3],
@@ -234,3 +262,23 @@ bool pbvh_bmesh_node_nearest_to_ray(PBVHNode *node,
bool use_original);
void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode);
+
+/* pbvh_bmesh.c */
+bool pbvh_trimesh_node_raycast(PBVHNode *node,
+ const float ray_start[3],
+ const float ray_normal[3],
+ struct IsectRayPrecalc *isect_precalc,
+ float *dist,
+ bool use_original,
+ SculptIdx *r_active_vertex_index,
+ float *r_face_normal);
+bool pbvh_trimesh_node_nearest_to_ray(PBVHNode *node,
+ const float ray_start[3],
+ const float ray_normal[3],
+ float *depth,
+ float *dist_sq,
+ bool use_original);
+
+void pbvh_trimesh_normals_update(PBVHNode **nodes, int totnode);
+
+#endif /* _PBVH_INTERN_H */
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
index e38848e2967..cdff85dfa4d 100644
--- a/source/blender/blenlib/BLI_ghash.h
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -53,6 +53,42 @@ typedef void *(*GHashValCopyFP)(const void *val);
typedef struct GHash GHash;
+#define GHASH_USE_MODULO_BUCKETS
+/* WARNING! Keep in sync with ugly _gh_Entry in header!!! */
+typedef struct Entry {
+ struct Entry *next;
+
+ void *key;
+} Entry;
+
+typedef struct GHashEntry {
+ Entry e;
+
+ void *val;
+} GHashEntry;
+
+typedef Entry GSetEntry;
+
+#define GHASH_ENTRY_SIZE(_is_gset) ((_is_gset) ? sizeof(GSetEntry) : sizeof(GHashEntry))
+
+struct GHash {
+ GHashHashFP hashfp;
+ GHashCmpFP cmpfp;
+
+ Entry **buckets;
+ struct BLI_mempool *entrypool;
+ uint nbuckets;
+ uint limit_grow, limit_shrink;
+#ifdef GHASH_USE_MODULO_BUCKETS
+ uint cursize, size_min;
+#else
+ uint bucket_mask, bucket_bit, bucket_bit_min;
+#endif
+
+ uint nentries;
+ uint flag;
+};
+
typedef struct GHashIterator {
GHash *gh;
struct Entry *curEntry;
@@ -131,7 +167,26 @@ GHashIterator *BLI_ghashIterator_new(GHash *gh) ATTR_MALLOC ATTR_WARN_UNUSED_RES
void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh);
void BLI_ghashIterator_free(GHashIterator *ghi);
-void BLI_ghashIterator_step(GHashIterator *ghi);
+//void BLI_ghashIterator_step(GHashIterator *ghi);
+
+/**
+* Steps the iterator to the next index.
+*
+* \param ghi: The iterator.
+*/
+BLI_INLINE void BLI_ghashIterator_step(GHashIterator *ghi)
+{
+ if (ghi->curEntry) {
+ ghi->curEntry = ghi->curEntry->next;
+ while (!ghi->curEntry) {
+ ghi->curBucket++;
+ if (ghi->curBucket == ghi->gh->nbuckets) {
+ break;
+ }
+ ghi->curEntry = ghi->gh->buckets[ghi->curBucket];
+ }
+ }
+}
BLI_INLINE void *BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT;
BLI_INLINE void *BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/blenlib/BLI_smallhash.h b/source/blender/blenlib/BLI_smallhash.h
index daea2fcd914..b62ddc68d1f 100644
--- a/source/blender/blenlib/BLI_smallhash.h
+++ b/source/blender/blenlib/BLI_smallhash.h
@@ -23,7 +23,14 @@
* \ingroup bli
*/
+#define USE_SMALLHASH_REMOVE
+
+#include "BLI_utildefines.h"
+
#include "BLI_compiler_attrs.h"
+#include "BLI_compiler_compat.h"
+#include "BLI_compiler_typecheck.h"
+#include "BLI_assert.h"
#ifdef __cplusplus
extern "C" {
@@ -48,29 +55,287 @@ typedef struct SmallHash {
typedef struct {
const SmallHash *sh;
- unsigned int i;
+ uintptr_t key;
+ void *val;
+ unsigned int i, done;
} SmallHashIter;
+
+#define SMHASH_KEY_UNUSED ((uintptr_t)(UINTPTR_MAX - 0))
+#define SMHASH_CELL_FREE ((void *)(UINTPTR_MAX - 1))
+#define SMHASH_CELL_UNUSED ((void *)(UINTPTR_MAX - 2))
+
+/* typically this re-assigns 'h' */
+#define SMHASH_NEXT(h, hoff) \
+ (CHECK_TYPE_INLINE(&(h), uintptr_t *), \
+ CHECK_TYPE_INLINE(&(hoff), uintptr_t *), \
+ ((h) + (((hoff) = ((hoff)*2) + 1), (hoff))))
+
+BLI_INLINE int smallhash_val_is_used(const void *val)
+{
+#ifdef USE_SMALLHASH_REMOVE
+ return !ELEM(val, SMHASH_CELL_FREE, SMHASH_CELL_UNUSED);
+#else
+ return (val != SMHASH_CELL_FREE);
+#endif
+}
+
+BLI_INLINE uintptr_t smallhash_key(const uintptr_t key)
+{
+ return key;
+}
+
+BLI_INLINE SmallHashEntry *smallhash_lookup(const SmallHash *sh, const uintptr_t key)
+{
+ SmallHashEntry *e;
+ uintptr_t h = smallhash_key(key);
+ uintptr_t hoff = 1;
+
+ BLI_assert(key != SMHASH_KEY_UNUSED);
+
+ /* note: there are always more buckets than entries,
+ * so we know there will always be a free bucket if the key isn't found. */
+ for (e = &sh->buckets[h % sh->nbuckets]; e->val != SMHASH_CELL_FREE;)
+ {
+ if (e->key == key) {
+ /* should never happen because unused keys are zero'd */
+ BLI_assert(e->val != SMHASH_CELL_UNUSED);
+
+ return e;
+ }
+
+ h = SMHASH_NEXT(h, hoff);
+ e = &sh->buckets[h % sh->nbuckets];
+ }
+
+ return NULL;
+}
+
+BLI_INLINE void *BLI_smallhash_lookup(const SmallHash *sh, uintptr_t key)
+{
+ SmallHashEntry *e = smallhash_lookup(sh, key);
+
+ return e ? e->val : NULL;
+}
+
+BLI_INLINE void **BLI_smallhash_lookup_p(const SmallHash *sh, uintptr_t key)
+{
+ SmallHashEntry *e = smallhash_lookup(sh, key);
+
+ return e ? &e->val : NULL;
+}
+
+BLI_INLINE bool BLI_smallhash_haskey(const SmallHash *sh, uintptr_t key)
+{
+ SmallHashEntry *e = smallhash_lookup(sh, key);
+
+ return (e != NULL);
+}
+
+BLI_INLINE int BLI_smallhash_len(const SmallHash *sh)
+{
+ return (int)sh->nentries;
+}
+
+BLI_INLINE SmallHashEntry *smallhash_iternext(SmallHashIter *iter, uintptr_t *key)
+{
+ while (iter->i < iter->sh->nbuckets) {
+ if (smallhash_val_is_used(iter->sh->buckets[iter->i].val)) {
+ SmallHashEntry *e = iter->sh->buckets + iter->i;
+
+ iter->key = e->key;
+ iter->val = e->val;
+
+ if (key) {
+ *key = iter->key;
+ }
+
+ iter->i++;
+ return e;
+ }
+
+ iter->i++;
+ }
+
+ iter->done = 1;
+ return NULL;
+}
+
+BLI_INLINE void *BLI_smallhash_iternext(SmallHashIter *iter, uintptr_t *key)
+{
+ SmallHashEntry *e = smallhash_iternext(iter, key);
+
+ return e ? e->val : NULL;
+}
+
+BLI_INLINE void **BLI_smallhash_iternext_p(SmallHashIter *iter, uintptr_t *key)
+{
+ SmallHashEntry *e = smallhash_iternext(iter, key);
+
+ return e ? &e->val : NULL;
+}
+
+BLI_INLINE void *BLI_smallhash_iternew(const SmallHash *sh, SmallHashIter *iter, uintptr_t *key)
+{
+ iter->sh = sh;
+ iter->i = 0;
+ iter->key = 0;
+ iter->val = NULL;
+ iter->done = 0;
+
+ return BLI_smallhash_iternext(iter, key);
+}
+void BLI_smallhash_clear(SmallHash *sh);
+
+BLI_INLINE void smallhash_resize_buckets(SmallHash *sh, const uint nbuckets);
+extern const uint BLI_ghash_hash_sizes[];
+
+/**
+* Check if the number of items in the smallhash is large enough to require more buckets.
+*/
+BLI_INLINE bool smallhash_test_expand_buckets(const uint nentries, const uint nbuckets)
+{
+ /* (approx * 1.25) */
+ return (nentries + (nentries >> 1) - (nentries >> 2)) > nbuckets;
+}
+
+# ifdef __SSE2__
+//BLI_INLINE SmallHashEntry *smallhash_lookup_simd(SmallHash *sh, const uintptr_t key) {
+ //__m128
+//}
+#endif
+
+BLI_INLINE SmallHashEntry *smallhash_lookup_first_free(SmallHash *sh, const uintptr_t key)
+{
+ SmallHashEntry *e;
+ uintptr_t h = smallhash_key(key);
+ uintptr_t hoff = 1;
+
+ for (e = &sh->buckets[h % sh->nbuckets]; smallhash_val_is_used(e->val);
+ h = SMHASH_NEXT(h, hoff), e = &sh->buckets[h % sh->nbuckets]) {
+ /* pass */
+ }
+
+ return e;
+}
+
+BLI_INLINE void smallhash_init_empty(SmallHash *sh)
+{
+ uint i;
+
+ for (i = 0; i < sh->nbuckets; i++) {
+ sh->buckets[i].key = SMHASH_KEY_UNUSED;
+ sh->buckets[i].val = SMHASH_CELL_FREE;
+ }
+}
+
+BLI_INLINE void smallhash_resize_buckets(SmallHash *sh, const uint nbuckets)
+{
+ SmallHashEntry *buckets_old = sh->buckets;
+ const uint nbuckets_old = sh->nbuckets;
+ const bool was_alloc = (buckets_old != sh->buckets_stack);
+ uint i = 0;
+
+ BLI_assert(sh->nbuckets != nbuckets);
+ if (nbuckets <= SMSTACKSIZE) {
+ const size_t size = sizeof(*buckets_old) * nbuckets_old;
+ buckets_old = alloca(size);
+ memcpy(buckets_old, sh->buckets, size);
+
+ sh->buckets = sh->buckets_stack;
+ }
+ else {
+ sh->buckets = MEM_mallocN(sizeof(*sh->buckets) * nbuckets, __func__);
+ }
+
+ sh->nbuckets = nbuckets;
+
+ smallhash_init_empty(sh);
+
+ for (i = 0; i < nbuckets_old; i++) {
+ if (smallhash_val_is_used(buckets_old[i].val)) {
+ SmallHashEntry *e = smallhash_lookup_first_free(sh, buckets_old[i].key);
+ e->key = buckets_old[i].key;
+ e->val = buckets_old[i].val;
+ }
+ }
+
+ if (was_alloc) {
+ MEM_freeN(buckets_old);
+ }
+}
+
+BLI_INLINE bool BLI_smallhash_ensure_p(SmallHash *sh, uintptr_t key, void ***item) {
+ SmallHashEntry *e;
+
+ if (UNLIKELY(smallhash_test_expand_buckets(++sh->nentries, sh->nbuckets))) {
+ smallhash_resize_buckets(sh, BLI_ghash_hash_sizes[++sh->cursize]);
+ }
+
+ uintptr_t h = smallhash_key(key);
+ uintptr_t hoff = 1;
+
+ e = smallhash_lookup(sh, key);
+ //*
+ for (e = &sh->buckets[h % sh->nbuckets]; e->key != key && smallhash_val_is_used((void*)e->val);
+ h = SMHASH_NEXT(h, hoff), e = &sh->buckets[h % sh->nbuckets]) {
+ }//*/
+
+ bool ret = true;
+
+ if (e->key != key) {
+ //e = smallhash_lookup_first_free(sh, key);
+ ret = false;
+ e->key = key;
+ } else {
+ e->val = NULL;
+ }
+
+ *item = &e->val;
+ return ret;
+}
+
+
+BLI_INLINE uintptr_t BLI_smallhash_iterkey(SmallHashIter *iter) {
+ return iter->key;
+}
+
+BLI_INLINE void *BLI_smallhash_iterval(SmallHashIter *iter) {
+ return (void*)iter->val;
+}
+
+BLI_INLINE void **BLI_smallhash_iternew_p(const SmallHash *sh, SmallHashIter *iter, uintptr_t *key)
+{
+ iter->sh = sh;
+ iter->i = 0;
+ iter->key = 0;
+ iter->val = NULL;
+ iter->done = 0;
+
+ return BLI_smallhash_iternext_p(iter, key);
+}
+
+#define SMALLHASH_ITER(iter, sh)\
+for (BLI_smallhash_iternew(sh, &(iter), NULL); !(iter).done; BLI_smallhash_iternext(&(iter), NULL))
+
void BLI_smallhash_init_ex(SmallHash *sh, const unsigned int nentries_reserve) ATTR_NONNULL(1);
void BLI_smallhash_init(SmallHash *sh) ATTR_NONNULL(1);
void BLI_smallhash_release(SmallHash *sh) ATTR_NONNULL(1);
void BLI_smallhash_insert(SmallHash *sh, uintptr_t key, void *item) ATTR_NONNULL(1);
bool BLI_smallhash_reinsert(SmallHash *sh, uintptr_t key, void *item) ATTR_NONNULL(1);
-bool BLI_smallhash_remove(SmallHash *sh, uintptr_t key) ATTR_NONNULL(1);
-void *BLI_smallhash_lookup(const SmallHash *sh, uintptr_t key)
- ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
-void **BLI_smallhash_lookup_p(const SmallHash *sh, uintptr_t key)
- ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
-bool BLI_smallhash_haskey(const SmallHash *sh, uintptr_t key) ATTR_NONNULL(1);
-int BLI_smallhash_len(const SmallHash *sh) ATTR_NONNULL(1);
-void *BLI_smallhash_iternext(SmallHashIter *iter, uintptr_t *key)
- ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
-void **BLI_smallhash_iternext_p(SmallHashIter *iter, uintptr_t *key)
- ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
-void *BLI_smallhash_iternew(const SmallHash *sh, SmallHashIter *iter, uintptr_t *key)
- ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
-void **BLI_smallhash_iternew_p(const SmallHash *sh, SmallHashIter *iter, uintptr_t *key)
- ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
+bool BLI_smallhash_remove(SmallHash *sh, uintptr_t key);
+void BLI_smallhash_reserve(SmallHash *sh, uint size);
+
+SmallHash *BLI_smallhash_new();
+SmallHash *BLI_smallhash_new_ex(int reserve);
+void BLI_smallhash_free(SmallHash *sh);
+
+//void *BLI_smallhash_lookup(const SmallHash *sh, uintptr_t key)
+// ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
+//void **BLI_smallhash_lookup_p(const SmallHash *sh, uintptr_t key)
+// ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
+//bool BLI_smallhash_haskey(const SmallHash *sh, uintptr_t key) ATTR_NONNULL(1);
+//int BLI_smallhash_len(const SmallHash *sh) ATTR_NONNULL(1);
/* void BLI_smallhash_print(SmallHash *sh); */ /* UNUSED */
#ifdef DEBUG
diff --git a/source/blender/blenlib/BLI_span.hh b/source/blender/blenlib/BLI_span.hh
index 5b4d2769f57..3b5ba69a8b3 100644
--- a/source/blender/blenlib/BLI_span.hh
+++ b/source/blender/blenlib/BLI_span.hh
@@ -300,6 +300,70 @@ template<typename T> class Span {
return counter;
}
+#ifdef _clang__
+ class iterator {
+ private:
+ int i_;
+
+ public:
+ explicit iterator(int i_ = 0) : i_(i_)
+ {
+ }
+ typedef T value_type;
+ typedef std::ptrdiff_t difference_type;
+ typedef T *pointer_type;
+ typedef T &reference_type;
+
+ iterator &operator++()
+ {
+ i_++;
+
+ return *this;
+ }
+
+ iterator operator++(int) const {
+ iterator ret = *this;
+
+ ++(*this);
+
+ return ret;
+ }
+
+ bool operator==(iterator other)
+ {
+ return i_ == other.i_;
+ }
+ bool operator!=(iterator other)
+ {
+ return i_ != other.i_;
+ }
+
+ iterator begin()
+ {
+ return iterator(span, 0);
+ }
+
+ iterator end()
+ {
+ return iterator(span, span.size_);
+ }
+
+ T &operator*() const
+ {
+ return data_[i_];
+ }
+ };
+
+ friend class iterator;
+ const iterator first() const
+ {
+ return iterator(0);
+ }
+
+ const iterator last() const {
+ return iterator(size_ - 1);
+ }
+#else
/**
* Return a reference to the first element in the array. This invokes undefined behavior when the
* array is empty.
@@ -319,6 +383,7 @@ template<typename T> class Span {
BLI_assert(size_ > 0);
return data_[size_ - 1];
}
+#endif
/**
* Returns the element at the given index. If the index is out of range, return the fallback
diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h
index d19b5393aa7..949931021f4 100644
--- a/source/blender/blenlib/BLI_threads.h
+++ b/source/blender/blenlib/BLI_threads.h
@@ -122,9 +122,16 @@ void BLI_spin_end(SpinLock *spin);
#define THREAD_LOCK_READ 1
#define THREAD_LOCK_WRITE 2
-#define BLI_RWLOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER
-
+#ifndef WIN32
typedef pthread_rwlock_t ThreadRWMutex;
+#define BLI_RWLOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER
+#else
+typedef struct {
+ void *data[4]; //stupid, to avoid windows.h here in the header
+ int have_exclusive;
+} ThreadRWMutex;
+#define BLI_RWLOCK_INITIALIZER {0} //just do what windows does
+#endif
void BLI_rw_mutex_init(ThreadRWMutex *mutex);
void BLI_rw_mutex_end(ThreadRWMutex *mutex);
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 473cc4d65f3..d8112957cfb 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -27,6 +27,7 @@ set(INC
../../../intern/guardedalloc
../../../intern/numaapi/include
../../../extern/wcwidth
+ ../../../extern
)
set(INC_SYS
@@ -42,6 +43,7 @@ set(SRC
intern/BLI_dial_2d.c
intern/BLI_dynstr.c
intern/BLI_filelist.c
+ intern/hashmap.cc
intern/BLI_ghash.c
intern/BLI_ghash_utils.c
intern/BLI_heap.c
@@ -52,6 +54,7 @@ set(SRC
intern/BLI_linklist_lockfree.c
intern/BLI_memarena.c
intern/BLI_memblock.c
+ intern/BLI_threadsafe_mempool.c
intern/BLI_memiter.c
intern/BLI_mempool.c
intern/BLI_timer.c
@@ -133,6 +136,7 @@ set(SRC
intern/task_pool.cc
intern/task_range.cc
intern/task_scheduler.cc
+ intern/hashmap_gen.h
intern/threads.cc
intern/time.c
intern/timecode.c
@@ -295,6 +299,7 @@ set(SRC
BLI_winstuff.h
PIL_time.h
PIL_time_utildefines.h
+ BLI_hashmap.h
)
set(LIB
@@ -372,6 +377,15 @@ set_source_files_properties(
PROPERTIES HEADER_FILE_ONLY TRUE
)
+#hashmap needs /Ob2 which is only used in Release, not RelWithDebInfo
+if(MSVC)
+ set(_findtemp "")
+ string(REPLACE "/Ob1" "/Ob3" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
+ string(REPLACE "/Ob1" "/Ob3" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
+ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /GS- ")
+ set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} /GS- ")
+endif()
+
blender_add_lib(bf_blenlib "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
if(WITH_GTESTS)
@@ -425,6 +439,7 @@ if(WITH_GTESTS)
tests/BLI_exception_safety_test_utils.hh
)
+
set(TEST_INC
../imbuf
)
diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c
index 69602cd4209..f8ce08d0350 100644
--- a/source/blender/blenlib/intern/BLI_ghash.c
+++ b/source/blender/blenlib/intern/BLI_ghash.c
@@ -45,7 +45,7 @@
/** \name Structs & Constants
* \{ */
-#define GHASH_USE_MODULO_BUCKETS
+
/**
* Next prime after `2^n` (skipping 2 & 3).
@@ -79,40 +79,6 @@ BLI_STATIC_ASSERT(ARRAY_SIZE(hashsizes) == GHASH_MAX_SIZE, "Invalid 'hashsizes'
#define GHASH_LIMIT_GROW(_nbkt) (((_nbkt)*3) / 4)
#define GHASH_LIMIT_SHRINK(_nbkt) (((_nbkt)*3) / 16)
-/* WARNING! Keep in sync with ugly _gh_Entry in header!!! */
-typedef struct Entry {
- struct Entry *next;
-
- void *key;
-} Entry;
-
-typedef struct GHashEntry {
- Entry e;
-
- void *val;
-} GHashEntry;
-
-typedef Entry GSetEntry;
-
-#define GHASH_ENTRY_SIZE(_is_gset) ((_is_gset) ? sizeof(GSetEntry) : sizeof(GHashEntry))
-
-struct GHash {
- GHashHashFP hashfp;
- GHashCmpFP cmpfp;
-
- Entry **buckets;
- struct BLI_mempool *entrypool;
- uint nbuckets;
- uint limit_grow, limit_shrink;
-#ifdef GHASH_USE_MODULO_BUCKETS
- uint cursize, size_min;
-#else
- uint bucket_mask, bucket_bit, bucket_bit_min;
-#endif
-
- uint nentries;
- uint flag;
-};
/** \} */
@@ -1083,6 +1049,7 @@ void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh)
*
* \param ghi: The iterator.
*/
+#if 0
void BLI_ghashIterator_step(GHashIterator *ghi)
{
if (ghi->curEntry) {
@@ -1096,6 +1063,7 @@ void BLI_ghashIterator_step(GHashIterator *ghi)
}
}
}
+#endif
/**
* Free a GHashIterator.
diff --git a/source/blender/blenlib/intern/math_boolean.cc b/source/blender/blenlib/intern/math_boolean.cc
index f8bf8676f50..b87ab815b20 100644
--- a/source/blender/blenlib/intern/math_boolean.cc
+++ b/source/blender/blenlib/intern/math_boolean.cc
@@ -45,6 +45,22 @@ int orient2d(const mpq2 &a, const mpq2 &b, const mpq2 &c)
return sgn(det);
}
+extern "C" int orient2d_exact(const float v1[2], const float v2[2], const float v3[2]) {
+ mpq2 a(v1[0], v1[1]);
+ mpq2 b(v2[0], v2[1]);
+ mpq2 c(v3[0], v3[1]);
+
+ return orient2d(a, b, c);
+}
+
+extern "C" int dorient2d_exact(const double v1[2], const double v2[2], const double v3[2]) {
+ mpq2 a(v1[0], v1[1]);
+ mpq2 b(v2[0], v2[1]);
+ mpq2 c(v3[0], v3[1]);
+
+ return orient2d(a, b, c);
+}
+
/**
Return +1 if d is in the oriented circle through a, b, and c.
* The oriented circle goes CCW through a, b, and c.
diff --git a/source/blender/blenlib/intern/smallhash.c b/source/blender/blenlib/intern/smallhash.c
index 4a2915ef24e..1b47003f5bf 100644
--- a/source/blender/blenlib/intern/smallhash.c
+++ b/source/blender/blenlib/intern/smallhash.c
@@ -54,139 +54,24 @@
#include "BLI_utildefines.h"
#include "BLI_smallhash.h"
-
#include "BLI_strict_flags.h"
-#define SMHASH_KEY_UNUSED ((uintptr_t)(UINTPTR_MAX - 0))
-#define SMHASH_CELL_FREE ((void *)(UINTPTR_MAX - 1))
-#define SMHASH_CELL_UNUSED ((void *)(UINTPTR_MAX - 2))
-
-/* typically this re-assigns 'h' */
-#define SMHASH_NEXT(h, hoff) \
- (CHECK_TYPE_INLINE(&(h), uint *), \
- CHECK_TYPE_INLINE(&(hoff), uint *), \
- ((h) + (((hoff) = ((hoff)*2) + 1), (hoff))))
-
/* nothing uses BLI_smallhash_remove yet */
-// #define USE_REMOVE
-BLI_INLINE bool smallhash_val_is_used(const void *val)
-{
-#ifdef USE_REMOVE
- return !ELEM(val, SMHASH_CELL_FREE, SMHASH_CELL_UNUSED);
-#else
- return (val != SMHASH_CELL_FREE);
-#endif
-}
extern const uint BLI_ghash_hash_sizes[];
#define hashsizes BLI_ghash_hash_sizes
-BLI_INLINE uint smallhash_key(const uintptr_t key)
-{
- return (uint)key;
-}
-
-/**
- * Check if the number of items in the smallhash is large enough to require more buckets.
- */
-BLI_INLINE bool smallhash_test_expand_buckets(const uint nentries, const uint nbuckets)
-{
- /* (approx * 1.5) */
- return (nentries + (nentries >> 1)) > nbuckets;
-}
-
-BLI_INLINE void smallhash_init_empty(SmallHash *sh)
-{
- uint i;
-
- for (i = 0; i < sh->nbuckets; i++) {
- sh->buckets[i].key = SMHASH_KEY_UNUSED;
- sh->buckets[i].val = SMHASH_CELL_FREE;
- }
-}
-
/**
* Increase initial bucket size to match a reserved amount.
*/
BLI_INLINE void smallhash_buckets_reserve(SmallHash *sh, const uint nentries_reserve)
{
- while (smallhash_test_expand_buckets(nentries_reserve, sh->nbuckets)) {
+ while (smallhash_test_expand_buckets(nentries_reserve, hashsizes[++sh->cursize])) {
sh->nbuckets = hashsizes[++sh->cursize];
}
}
-BLI_INLINE SmallHashEntry *smallhash_lookup(const SmallHash *sh, const uintptr_t key)
-{
- SmallHashEntry *e;
- uint h = smallhash_key(key);
- uint hoff = 1;
-
- BLI_assert(key != SMHASH_KEY_UNUSED);
-
- /* note: there are always more buckets than entries,
- * so we know there will always be a free bucket if the key isn't found. */
- for (e = &sh->buckets[h % sh->nbuckets]; e->val != SMHASH_CELL_FREE;
- h = SMHASH_NEXT(h, hoff), e = &sh->buckets[h % sh->nbuckets]) {
- if (e->key == key) {
- /* should never happen because unused keys are zero'd */
- BLI_assert(e->val != SMHASH_CELL_UNUSED);
- return e;
- }
- }
-
- return NULL;
-}
-
-BLI_INLINE SmallHashEntry *smallhash_lookup_first_free(SmallHash *sh, const uintptr_t key)
-{
- SmallHashEntry *e;
- uint h = smallhash_key(key);
- uint hoff = 1;
-
- for (e = &sh->buckets[h % sh->nbuckets]; smallhash_val_is_used(e->val);
- h = SMHASH_NEXT(h, hoff), e = &sh->buckets[h % sh->nbuckets]) {
- /* pass */
- }
-
- return e;
-}
-
-BLI_INLINE void smallhash_resize_buckets(SmallHash *sh, const uint nbuckets)
-{
- SmallHashEntry *buckets_old = sh->buckets;
- const uint nbuckets_old = sh->nbuckets;
- const bool was_alloc = (buckets_old != sh->buckets_stack);
- uint i = 0;
-
- BLI_assert(sh->nbuckets != nbuckets);
- if (nbuckets <= SMSTACKSIZE) {
- const size_t size = sizeof(*buckets_old) * nbuckets_old;
- buckets_old = alloca(size);
- memcpy(buckets_old, sh->buckets, size);
-
- sh->buckets = sh->buckets_stack;
- }
- else {
- sh->buckets = MEM_mallocN(sizeof(*sh->buckets) * nbuckets, __func__);
- }
-
- sh->nbuckets = nbuckets;
-
- smallhash_init_empty(sh);
-
- for (i = 0; i < nbuckets_old; i++) {
- if (smallhash_val_is_used(buckets_old[i].val)) {
- SmallHashEntry *e = smallhash_lookup_first_free(sh, buckets_old[i].key);
- e->key = buckets_old[i].key;
- e->val = buckets_old[i].val;
- }
- }
-
- if (was_alloc) {
- MEM_freeN(buckets_old);
- }
-}
void BLI_smallhash_init_ex(SmallHash *sh, const uint nentries_reserve)
{
@@ -222,6 +107,29 @@ void BLI_smallhash_release(SmallHash *sh)
}
}
+void BLI_smallhash_clear(SmallHash *sh) {
+ unsigned int i;
+ SmallHashEntry *entry = sh->buckets;
+
+ for (i=0; i<sh->nbuckets; i++, entry++) {
+ entry->key = SMHASH_KEY_UNUSED;
+ entry->val = SMHASH_CELL_FREE;
+ }
+
+ sh->nentries = 0;
+}
+
+void BLI_smallhash_reserve(SmallHash *sh, uint size) {
+ int cursize = sh->cursize;
+
+ while (smallhash_test_expand_buckets(size, hashsizes[cursize])) {
+ cursize++;
+ }
+
+ sh->cursize = cursize;
+ smallhash_resize_buckets(sh, hashsizes[cursize]);
+}
+
void BLI_smallhash_insert(SmallHash *sh, uintptr_t key, void *item)
{
SmallHashEntry *e;
@@ -239,6 +147,7 @@ void BLI_smallhash_insert(SmallHash *sh, uintptr_t key, void *item)
e->val = item;
}
+
/**
* Inserts a new value to a key that may already be in ghash.
*
@@ -258,7 +167,7 @@ bool BLI_smallhash_reinsert(SmallHash *sh, uintptr_t key, void *item)
return true;
}
-#ifdef USE_REMOVE
+#ifdef USE_SMALLHASH_REMOVE
bool BLI_smallhash_remove(SmallHash *sh, uintptr_t key)
{
SmallHashEntry *e = smallhash_lookup(sh, key);
@@ -276,78 +185,7 @@ bool BLI_smallhash_remove(SmallHash *sh, uintptr_t key)
}
#endif
-void *BLI_smallhash_lookup(const SmallHash *sh, uintptr_t key)
-{
- SmallHashEntry *e = smallhash_lookup(sh, key);
-
- return e ? e->val : NULL;
-}
-
-void **BLI_smallhash_lookup_p(const SmallHash *sh, uintptr_t key)
-{
- SmallHashEntry *e = smallhash_lookup(sh, key);
-
- return e ? &e->val : NULL;
-}
-
-bool BLI_smallhash_haskey(const SmallHash *sh, uintptr_t key)
-{
- SmallHashEntry *e = smallhash_lookup(sh, key);
-
- return (e != NULL);
-}
-
-int BLI_smallhash_len(const SmallHash *sh)
-{
- return (int)sh->nentries;
-}
-
-BLI_INLINE SmallHashEntry *smallhash_iternext(SmallHashIter *iter, uintptr_t *key)
-{
- while (iter->i < iter->sh->nbuckets) {
- if (smallhash_val_is_used(iter->sh->buckets[iter->i].val)) {
- if (key) {
- *key = iter->sh->buckets[iter->i].key;
- }
-
- return &iter->sh->buckets[iter->i++];
- }
-
- iter->i++;
- }
-
- return NULL;
-}
-
-void *BLI_smallhash_iternext(SmallHashIter *iter, uintptr_t *key)
-{
- SmallHashEntry *e = smallhash_iternext(iter, key);
-
- return e ? e->val : NULL;
-}
-void **BLI_smallhash_iternext_p(SmallHashIter *iter, uintptr_t *key)
-{
- SmallHashEntry *e = smallhash_iternext(iter, key);
-
- return e ? &e->val : NULL;
-}
-
-void *BLI_smallhash_iternew(const SmallHash *sh, SmallHashIter *iter, uintptr_t *key)
-{
- iter->sh = sh;
- iter->i = 0;
-
- return BLI_smallhash_iternext(iter, key);
-}
-
-void **BLI_smallhash_iternew_p(const SmallHash *sh, SmallHashIter *iter, uintptr_t *key)
-{
- iter->sh = sh;
- iter->i = 0;
-
- return BLI_smallhash_iternext_p(iter, key);
-}
/** \name Debugging & Introspection
* \{ */
@@ -407,8 +245,8 @@ double BLI_smallhash_calc_quality(SmallHash *sh)
if (sh->buckets[i].key != SMHASH_KEY_UNUSED) {
uint64_t count = 0;
SmallHashEntry *e, *e_final = &sh->buckets[i];
- uint h = smallhash_key(e_final->key);
- uint hoff = 1;
+ uintptr_t h = smallhash_key(e_final->key);
+ uintptr_t hoff = 1;
for (e = &sh->buckets[h % sh->nbuckets]; e != e_final;
h = SMHASH_NEXT(h, hoff), e = &sh->buckets[h % sh->nbuckets]) {
@@ -423,3 +261,19 @@ double BLI_smallhash_calc_quality(SmallHash *sh)
#endif
/** \} */
+SmallHash *BLI_smallhash_new() {
+ SmallHash *sh = MEM_callocN(sizeof(SmallHash), "SmallHash");
+ BLI_smallhash_init(sh);
+ return sh;
+}
+
+SmallHash *BLI_smallhash_new_ex(int reserve) {
+ SmallHash *sh = MEM_callocN(sizeof(SmallHash), "SmallHash");
+ BLI_smallhash_init_ex(sh, reserve);
+ return sh;
+}
+
+void BLI_smallhash_free(SmallHash *sh) {
+ BLI_smallhash_release(sh);
+ MEM_freeN(sh);
+}
diff --git a/source/blender/blenlib/intern/task_pool.cc b/source/blender/blenlib/intern/task_pool.cc
index cf328ec407c..b277118af5d 100644
--- a/source/blender/blenlib/intern/task_pool.cc
+++ b/source/blender/blenlib/intern/task_pool.cc
@@ -90,7 +90,7 @@ class Task {
other.freedata = NULL;
}
-#if defined(WITH_TBB) && TBB_INTERFACE_VERSION_MAJOR < 10
+#if 1 //defined(WITH_TBB) && TBB_INTERFACE_VERSION_MAJOR < 10
Task(const Task &other)
: pool(other.pool),
run(other.run),
diff --git a/source/blender/blenlib/intern/threads.cc b/source/blender/blenlib/intern/threads.cc
index a2b1a12c783..35e488b07a0 100644
--- a/source/blender/blenlib/intern/threads.cc
+++ b/source/blender/blenlib/intern/threads.cc
@@ -509,29 +509,54 @@ void BLI_spin_end(SpinLock *spin)
/* Read/Write Mutex Lock */
+#define GET_RW_LOCK(mutex) reinterpret_cast<SRWLOCK*>(&mutex->data[0])
+
void BLI_rw_mutex_init(ThreadRWMutex *mutex)
{
+#ifndef WIN32
pthread_rwlock_init(mutex, nullptr);
+#else
+ InitializeSRWLock(GET_RW_LOCK(mutex));
+#endif
}
void BLI_rw_mutex_lock(ThreadRWMutex *mutex, int mode)
{
+#ifndef WIN32
if (mode == THREAD_LOCK_READ) {
pthread_rwlock_rdlock(mutex);
}
else {
pthread_rwlock_wrlock(mutex);
}
+#else
+ if (mode == THREAD_LOCK_READ) {
+ AcquireSRWLockShared(GET_RW_LOCK(mutex));
+ } else {
+ AcquireSRWLockExclusive(GET_RW_LOCK(mutex));
+ mutex->have_exclusive = 1;
+ }
+#endif
}
void BLI_rw_mutex_unlock(ThreadRWMutex *mutex)
{
+#ifndef WIN32
pthread_rwlock_unlock(mutex);
+#else
+ if (!mutex->have_exclusive) {
+ ReleaseSRWLockShared(GET_RW_LOCK(mutex));
+ } else {
+ mutex->have_exclusive = 0;
+ ReleaseSRWLockExclusive(GET_RW_LOCK(mutex));
+ }
+#endif
+
}
void BLI_rw_mutex_end(ThreadRWMutex *mutex)
{
- pthread_rwlock_destroy(mutex);
+
}
ThreadRWMutex *BLI_rw_mutex_alloc(void)
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index c44e9b5efff..4742733d297 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -4981,6 +4981,12 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (!MAIN_VERSION_ATLEAST(bmain, 283, 12)) {
+ for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ if (scene->r.hair_cyl_res == 0) {
+ scene->r.hair_cyl_res = 6;
+ }
+ }
+
/* Activate f-curve drawing in the sequencer. */
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
for (ScrArea *area = screen->areabase.first; area; area = area->next) {
diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c
index 0bbe86d2d2f..3ee59bffa6b 100644
--- a/source/blender/bmesh/intern/bmesh_interp.c
+++ b/source/blender/bmesh/intern/bmesh_interp.c
@@ -33,6 +33,8 @@
#include "BLI_memarena.h"
#include "BLI_task.h"
+#include "BLI_threadsafe_mempool.h"
+
#include "BKE_customdata.h"
#include "BKE_multires.h"
@@ -816,7 +818,7 @@ void BM_vert_interp_from_face(BMesh *bm, BMVert *v_dst, const BMFace *f_src)
static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
{
BMIter iter;
- BLI_mempool *oldpool = olddata->pool;
+ BLI_ThreadSafePool *oldpool = olddata->tpool;
void *block;
if (data == &bm->vdata) {
@@ -880,13 +882,14 @@ static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
}
if (oldpool) {
- /* this should never happen but can when dissolve fails - T28960. */
- BLI_assert(data->pool != oldpool);
+ /* this should never happen but can when dissolve fails - [#28960] */
+ BLI_assert(data->tpool != oldpool);
- BLI_mempool_destroy(oldpool);
+ BLI_safepool_destroy(oldpool);
}
}
+
void BM_data_layer_add(BMesh *bm, CustomData *data, int type)
{
CustomData olddata;
@@ -895,7 +898,7 @@ void BM_data_layer_add(BMesh *bm, CustomData *data, int type)
olddata.layers = (olddata.layers) ? MEM_dupallocN(olddata.layers) : NULL;
/* the pool is now owned by olddata and must not be shared */
- data->pool = NULL;
+ data->tpool = NULL;
CustomData_add_layer(data, type, CD_DEFAULT, NULL, 0);
@@ -913,7 +916,7 @@ void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const char *
olddata.layers = (olddata.layers) ? MEM_dupallocN(olddata.layers) : NULL;
/* the pool is now owned by olddata and must not be shared */
- data->pool = NULL;
+ data->tpool = NULL;
CustomData_add_layer_named(data, type, CD_DEFAULT, NULL, 0, name);
@@ -932,7 +935,7 @@ void BM_data_layer_free(BMesh *bm, CustomData *data, int type)
olddata.layers = (olddata.layers) ? MEM_dupallocN(olddata.layers) : NULL;
/* the pool is now owned by olddata and must not be shared */
- data->pool = NULL;
+ data->tpool = NULL;
has_layer = CustomData_free_layer_active(data, type, 0);
/* assert because its expensive to realloc - better not do if layer isnt present */
@@ -954,7 +957,7 @@ void BM_data_layer_free_n(BMesh *bm, CustomData *data, int type, int n)
olddata.layers = (olddata.layers) ? MEM_dupallocN(olddata.layers) : NULL;
/* the pool is now owned by olddata and must not be shared */
- data->pool = NULL;
+ data->tpool = NULL;
has_layer = CustomData_free_layer(data, type, 0, CustomData_get_layer_index_n(data, type, n));
/* assert because its expensive to realloc - better not do if layer isnt present */
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index 8eed3141c7f..51a36f11c59 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -32,6 +32,7 @@
#include "BLI_stack.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
+#include "BLI_threadsafe_mempool.h"
#include "BKE_editmesh.h"
#include "BKE_global.h"
@@ -222,16 +223,16 @@ void BM_mesh_data_free(BMesh *bm)
/* Free custom data pools, This should probably go in CustomData_free? */
if (bm->vdata.totlayer) {
- BLI_mempool_destroy(bm->vdata.pool);
+ BLI_safepool_destroy(bm->vdata.tpool);
}
if (bm->edata.totlayer) {
- BLI_mempool_destroy(bm->edata.pool);
+ BLI_safepool_destroy(bm->edata.tpool);
}
if (bm->ldata.totlayer) {
- BLI_mempool_destroy(bm->ldata.pool);
+ BLI_safepool_destroy(bm->ldata.tpool);
}
if (bm->pdata.totlayer) {
- BLI_mempool_destroy(bm->pdata.pool);
+ BLI_safepool_destroy(bm->pdata.tpool);
}
/* free custom data */
diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.c b/source/blender/bmesh/intern/bmesh_mesh_convert.c
index 90b0cca4b9c..3a3c2c35786 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_convert.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.c
@@ -107,9 +107,9 @@ void BM_mesh_cd_flag_ensure(BMesh *bm, Mesh *mesh, const char cd_flag)
void BM_mesh_cd_flag_apply(BMesh *bm, const char cd_flag)
{
/* CustomData_bmesh_init_pool() must run first */
- BLI_assert(bm->vdata.totlayer == 0 || bm->vdata.pool != NULL);
- BLI_assert(bm->edata.totlayer == 0 || bm->edata.pool != NULL);
- BLI_assert(bm->pdata.totlayer == 0 || bm->pdata.pool != NULL);
+ BLI_assert(bm->vdata.totlayer == 0 || bm->vdata.tpool != NULL);
+ BLI_assert(bm->edata.totlayer == 0 || bm->edata.tpool != NULL);
+ BLI_assert(bm->pdata.totlayer == 0 || bm->pdata.tpool != NULL);
if (cd_flag & ME_CDFLAG_VERT_BWEIGHT) {
if (!CustomData_has_layer(&bm->vdata, CD_BWEIGHT)) {
diff --git a/source/blender/bmesh/operators/bmo_fill_grid.c b/source/blender/bmesh/operators/bmo_fill_grid.c
index 6986655c6de..6550640a69f 100644
--- a/source/blender/bmesh/operators/bmo_fill_grid.c
+++ b/source/blender/bmesh/operators/bmo_fill_grid.c
@@ -28,6 +28,7 @@
#include "BKE_customdata.h"
#include "bmesh.h"
+#include "BLI_ghash.h"
#include "intern/bmesh_operators_private.h" /* own include */
diff --git a/source/blender/bmesh/operators/bmo_hull.c b/source/blender/bmesh/operators/bmo_hull.c
index 84938084aec..db5f7a5e3ee 100644
--- a/source/blender/bmesh/operators/bmo_hull.c
+++ b/source/blender/bmesh/operators/bmo_hull.c
@@ -34,6 +34,7 @@
* values would be though */
# include "bmesh.h"
+#include "BLI_ghash.h"
# include "intern/bmesh_operators_private.h" /* own include */
diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
index 7900aba0086..e3dd352030f 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
@@ -693,7 +693,7 @@ static void bm_edge_collapse_loop_customdata(
{
/* Disable seam check - the seam check would have to be done per layer,
* its not really that important. */
- //#define USE_SEAM
+ #define USE_SEAM
/* these don't need to be updated, since they will get removed when the edge collapses */
BMLoop *l_clear, *l_other;
const bool is_manifold = BM_edge_is_manifold(l->e);
diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c
index 52d1fcfdb80..b9f5f1cddf3 100644
--- a/source/blender/draw/intern/draw_cache_impl_particles.c
+++ b/source/blender/draw/intern/draw_cache_impl_particles.c
@@ -1031,7 +1031,7 @@ static void particle_batch_cache_ensure_procedural_indices(PTCacheEdit *edit,
int thickness_res,
int subdiv)
{
- BLI_assert(thickness_res <= MAX_THICKRES); /* Cylinder strip not currently supported. */
+ BLI_assert(thickness_res <= MAX_THICKRES);
if (cache->final[subdiv].proc_hairs[thickness_res - 1] != NULL) {
return;
diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c
index cc0aa09ed97..a13d9f31c83 100644
--- a/source/blender/draw/intern/draw_hair.c
+++ b/source/blender/draw/intern/draw_hair.c
@@ -177,7 +177,19 @@ GPUVertBuf *DRW_hair_pos_buffer_get(Object *object, ParticleSystem *psys, Modifi
Scene *scene = draw_ctx->scene;
int subdiv = scene->r.hair_subdiv;
- int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2;
+ int thickness_res = 1;
+
+ switch (scene->r.hair_type) {
+ case SCE_HAIR_SHAPE_STRAND:
+ thickness_res = 1;
+ break;
+ case SCE_HAIR_SHAPE_STRIP:
+ thickness_res = 2;
+ break;
+ case SCE_HAIR_SHAPE_CYLINDER:
+ thickness_res = MAX2(scene->r.hair_cyl_res, 3)*2;
+ break;
+ }
ParticleHairCache *cache = drw_hair_particle_cache_get(object, psys, md, subdiv, thickness_res);
diff --git a/source/blender/draw/intern/draw_hair_private.h b/source/blender/draw/intern/draw_hair_private.h
index 33abae156cc..d634964405d 100644
--- a/source/blender/draw/intern/draw_hair_private.h
+++ b/source/blender/draw/intern/draw_hair_private.h
@@ -25,7 +25,7 @@
#define MAX_LAYER_NAME_CT 4 /* u0123456789, u, au, a0123456789 */
#define MAX_LAYER_NAME_LEN GPU_MAX_SAFE_ATTR_NAME + 2
-#define MAX_THICKRES 2 /* see eHairType */
+#define MAX_THICKRES 128 /* see eHairType */
#define MAX_HAIR_SUBDIV 4 /* see hair_subdiv rna */
struct ModifierData;
diff --git a/source/blender/draw/intern/shaders/common_hair_lib.glsl b/source/blender/draw/intern/shaders/common_hair_lib.glsl
index 8684d82f228..a4d94d66ae4 100644
--- a/source/blender/draw/intern/shaders/common_hair_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_hair_lib.glsl
@@ -12,6 +12,13 @@
*/
uniform int hairStrandsRes = 8;
+#ifndef M_PI
+#define M_PI 3.14159265358979323846 /* pi */
+#endif
+#ifndef M_2PI
+#define M_2PI 6.28318530717958647692 /* 2*pi */
+#endif
+
/**
* hairThicknessRes : Subdiv around the hair.
* 1 - Wire Hair: Only one pixel thick, independent of view distance.
@@ -170,7 +177,7 @@ void hair_get_pos_tan_binor_time(bool is_persp,
thickness = hair_shaperadius(hairRadShape, hairRadRoot, hairRadTip, time);
- if (hairThicknessRes > 1) {
+ if (hairThicknessRes == 2) {
thick_time = float(gl_VertexID % hairThicknessRes) / float(hairThicknessRes - 1);
thick_time = thickness * (thick_time * 2.0 - 1.0);
@@ -179,6 +186,72 @@ void hair_get_pos_tan_binor_time(bool is_persp,
float scale = 1.0 / length(mat3(invmodel_mat) * wbinor);
wpos += wbinor * thick_time * scale;
+ } else if (hairThicknessRes > 2) { //cylinder
+ vec4 data2;
+ vec4 data3;
+ vec3 wpos2;
+ vec3 wtan2;
+
+ int id2 = time > 0.0 ? id - 1 : id;
+ data2 = texelFetch(hairPointBuffer, id2);
+
+ int id3 = data2.point_time > 0.0 ? id2 - 1 : id2;
+ data3 = texelFetch(hairPointBuffer, id3);
+
+ wtan = data.point_position - data2.point_position;
+ wtan2 = data2.point_position - data3.point_position;
+
+ wtan = -normalize(mat3(obmat) * wtan);
+ wtan2 = -normalize(mat3(obmat) * wtan2);
+
+ wpos2 = data2.point_position;
+ wpos2 = (obmat * vec4(wpos2, 1.0)).xyz;
+
+ //as a triangle strip, we alternative between current and next ring every other vert
+ if (gl_VertexID % 2 == 0) {
+ thickness = hair_shaperadius(hairRadShape, hairRadRoot, hairRadTip, data2.point_time);
+ wtan = wtan2;
+ time = data2.point_time;
+ }
+
+ thick_time = float((gl_VertexID/2) % (hairThicknessRes/2)) / float((hairThicknessRes/2) - 1);
+ thick_time *= M_2PI;
+
+ //build reference frame
+
+ //find compatible world axis
+ vec3 axis;
+ if (abs(wtan[0]) >= abs(wtan[1]) && abs(wtan[0]) >= abs(wtan[2])) {
+ axis = vec3(0.0, 1.0, 0.0);
+ } else if (abs(wtan[1]) >= abs(wtan[0]) && abs(wtan[1]) >= abs(wtan[2])) {
+ axis = vec3(0.0, 0.0, 1.0);
+ } else {
+ axis = vec3(1.0, 0.0, 0.0);
+ }
+
+ //make frame
+ vec3 dx = normalize(cross(axis, wtan));
+ vec3 dy = normalize(cross(wtan, dx));
+
+ float x = sin(thick_time);
+ float y = cos(thick_time);
+
+ wbinor = dx*x + dy*y;
+ wbinor = normalize(mat3(obmat) * wbinor);
+
+
+ /* Take object scale into account.
+ * NOTE: This only works fine with uniform scaling. */
+ float scale = 1.0 / length(mat3(invmodel_mat) * wbinor);
+
+ x *= scale * thickness;
+ y *= scale * thickness;
+
+ if (gl_VertexID % 2 == 1) {
+ wpos += dx*x + dy*y;
+ } else {
+ wpos = wpos2 + (dx*x + dy*y);
+ }
}
}
diff --git a/source/blender/editors/interface/interface_template_search_menu.c b/source/blender/editors/interface/interface_template_search_menu.c
index 5bde51846a8..0dac2b5cd41 100644
--- a/source/blender/editors/interface/interface_template_search_menu.c
+++ b/source/blender/editors/interface/interface_template_search_menu.c
@@ -33,6 +33,7 @@
#include "DNA_shader_fx_types.h"
#include "DNA_texture_types.h"
+#include "BLI_ghash.h"
#include "BLI_alloca.h"
#include "BLI_dynstr.h"
#include "BLI_ghash.h"
diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c
index f94d3ba5a70..72823f34d7f 100644
--- a/source/blender/editors/mesh/editmesh_select_similar.c
+++ b/source/blender/editors/mesh/editmesh_select_similar.c
@@ -27,6 +27,7 @@
#include "BLI_kdtree.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLI_ghash.h"
#include "BKE_context.h"
#include "BKE_editmesh.h"
diff --git a/source/blender/editors/object/object_remesh.c b/source/blender/editors/object/object_remesh.c
index cc3230dff7b..56dc49a68cf 100644
--- a/source/blender/editors/object/object_remesh.c
+++ b/source/blender/editors/object/object_remesh.c
@@ -113,7 +113,7 @@ static bool object_remesh_poll(bContext *C)
return false;
}
- if (ob->mode == OB_MODE_SCULPT && ob->sculpt->bm) {
+ if (ob->mode == OB_MODE_SCULPT && (ob->sculpt->bm || ob->sculpt->tm)) {
CTX_wm_operator_poll_msg_set(C, "The remesher cannot run with dyntopo activated");
return false;
}
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 1a8c74c59b1..31f75cfe887 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -624,6 +624,7 @@ void ED_region_do_draw(bContext *C, ARegion *region)
SpaceLink *sl = area->spacedata.first;
PointerRNA ptr;
+
RNA_pointer_create(&screen->id, &RNA_Space, sl, &ptr);
wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index 930f9890dd9..8770d42a9a9 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -22,6 +22,7 @@ set(INC
../../blenlib
../../blentranslation
../../bmesh
+ ../../trimesh
../../depsgraph
../../draw
../../gpu
@@ -80,6 +81,7 @@ set(SRC
set(LIB
bf_blenkernel
bf_blenlib
+ bf_trimesh
)
if(WITH_INTERNATIONAL)
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index 2e24c2533c5..18431ce6502 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -1214,7 +1214,7 @@ typedef struct PaintCursorContext {
/* Sculpt related data. */
Sculpt *sd;
SculptSession *ss;
- int prev_active_vertex_index;
+ SculptIdx prev_active_vertex_index;
bool is_stroke_active;
bool is_cursor_over_mesh;
bool is_multires;
diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c
index e5d682c27d9..c271a4b668b 100644
--- a/source/blender/editors/sculpt_paint/paint_hide.c
+++ b/source/blender/editors/sculpt_paint/paint_hide.c
@@ -53,6 +53,7 @@
#include "RNA_define.h"
#include "bmesh.h"
+#include "trimesh.h"
#include "paint_intern.h"
@@ -286,6 +287,94 @@ static void partialvis_update_bmesh(Object *ob,
}
}
+static void partialvis_update_trimesh_verts(TM_TriMesh *bm,
+ TMElemSet *verts,
+ PartialVisAction action,
+ PartialVisArea area,
+ float planes[4][4],
+ bool *any_changed,
+ bool *any_visible)
+{
+ TMVert *v;
+
+ TMS_ITER (v, verts) {
+ float *vmask = CustomData_bmesh_get(&bm->vdata, v->customdata, CD_PAINT_MASK);
+
+ /* Hide vertex if in the hide volume. */
+ if (is_effected(area, planes, v->co, *vmask)) {
+ if (action == PARTIALVIS_HIDE) {
+ TM_elem_flag_enable(v, TM_ELEM_HIDDEN);
+ }
+ else {
+ TM_elem_flag_disable(v, TM_ELEM_HIDDEN);
+ }
+ (*any_changed) = true;
+ }
+
+ if (!TM_elem_flag_test(v, TM_ELEM_HIDDEN)) {
+ (*any_visible) = true;
+ }
+ } TMS_ITER_END
+}
+
+/* Return true if all vertices in the face are visible, false otherwise */
+static bool paint_is_trimesh_face_hidden(TMFace *f)
+{
+ bool ret = f->v1->flag & TM_ELEM_HIDDEN;
+ ret = ret || (f->v2->flag & TM_ELEM_HIDDEN);
+ ret = ret || (f->v3->flag & TM_ELEM_HIDDEN);
+
+ return ret;
+}
+
+static void partialvis_update_trimesh_faces(GSet *faces)
+{
+ GSetIterator gs_iter;
+
+ GSET_ITER (gs_iter, faces) {
+ TMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+
+ if (paint_is_trimesh_face_hidden(f)) {
+ TM_elem_flag_enable(f, TM_ELEM_HIDDEN);
+ }
+ else {
+ TM_elem_flag_disable(f, TM_ELEM_HIDDEN);
+ }
+ }
+}
+
+static void partialvis_update_trimesh(Object *ob,
+ PBVH *pbvh,
+ PBVHNode *node,
+ PartialVisAction action,
+ PartialVisArea area,
+ float planes[4][4])
+{
+ TM_TriMesh *bm;
+ TMElemSet *unique, *other;
+ GSet *faces;
+ bool any_changed = false, any_visible = false;
+
+ bm = BKE_pbvh_get_trimesh(pbvh);
+ unique = BKE_pbvh_trimesh_node_unique_verts(node);
+ other = BKE_pbvh_trimesh_node_other_verts(node);
+ faces = BKE_pbvh_trimesh_node_faces(node);
+
+ SCULPT_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN);
+
+ partialvis_update_trimesh_verts(bm, unique, action, area, planes, &any_changed, &any_visible);
+
+ partialvis_update_trimesh_verts(bm, other, action, area, planes, &any_changed, &any_visible);
+
+ /* Finally loop over node faces and tag the ones that are fully hidden. */
+ partialvis_update_trimesh_faces(faces);
+
+ if (any_changed) {
+ BKE_pbvh_node_mark_rebuild_draw(node);
+ BKE_pbvh_node_fully_hidden_set(node, !any_visible);
+ }
+}
+
static void rect_from_props(rcti *rect, PointerRNA *ptr)
{
rect->xmin = RNA_int_get(ptr, "xmin");
@@ -384,6 +473,9 @@ static int hide_show_exec(bContext *C, wmOperator *op)
case PBVH_BMESH:
partialvis_update_bmesh(ob, pbvh, nodes[i], action, area, clip_planes);
break;
+ case PBVH_TRIMESH:
+ partialvis_update_trimesh(ob, pbvh, nodes[i], action, area, clip_planes);
+ break;
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index cfb73153371..420d5c2e78a 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -62,6 +62,7 @@
#include "bmesh.h"
#include "bmesh_tools.h"
+#include "trimesh.h"
#include "tools/bmesh_boolean.h"
#include "paint_intern.h"
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 6472da48f40..0ab7c823408 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -74,6 +74,7 @@
#include "BKE_ccg.h"
#include "bmesh.h"
+#include "trimesh.h"
#include "paint_intern.h" /* own include */
#include "sculpt_intern.h"
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 16b5d770fa2..8eb557f95c3 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -96,6 +96,7 @@
#include "bmesh.h"
#include "bmesh_tools.h"
+#include "trimesh.h"
#include <math.h>
#include <stdlib.h>
@@ -115,6 +116,10 @@ void SCULPT_vertex_random_access_ensure(SculptSession *ss)
BM_mesh_elem_index_ensure(ss->bm, BM_VERT);
BM_mesh_elem_table_ensure(ss->bm, BM_VERT);
}
+ else if (BKE_pbvh_type(ss->pbvh) == PBVH_TRIMESH) {
+ TM_mesh_elem_index_ensure(ss->tm, TM_VERTEX);
+ TM_mesh_elem_table_ensure(ss->tm, TM_VERTEX);
+ }
}
int SCULPT_vertex_count_get(SculptSession *ss)
@@ -124,6 +129,8 @@ int SCULPT_vertex_count_get(SculptSession *ss)
return ss->totvert;
case PBVH_BMESH:
return BM_mesh_elem_count(BKE_pbvh_get_bmesh(ss->pbvh), BM_VERT);
+ case PBVH_TRIMESH:
+ return TM_mesh_elem_count(BKE_pbvh_get_trimesh(ss->pbvh), TM_VERTEX);
case PBVH_GRIDS:
return BKE_pbvh_get_grid_num_vertices(ss->pbvh);
}
@@ -131,7 +138,7 @@ int SCULPT_vertex_count_get(SculptSession *ss)
return 0;
}
-const float *SCULPT_vertex_co_get(SculptSession *ss, int index)
+const float *SCULPT_vertex_co_get(SculptSession *ss, SculptIdx index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
@@ -143,6 +150,10 @@ const float *SCULPT_vertex_co_get(SculptSession *ss, int index)
}
case PBVH_BMESH:
return BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->co;
+ case PBVH_TRIMESH: {
+ TMVert *v = (TMVert *)index;
+ return v->co;
+ }
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
const int grid_index = index / key->grid_area;
@@ -154,7 +165,7 @@ const float *SCULPT_vertex_co_get(SculptSession *ss, int index)
return NULL;
}
-const float *SCULPT_vertex_color_get(SculptSession *ss, int index)
+const float *SCULPT_vertex_color_get(SculptSession *ss, SculptIdx index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
@@ -163,13 +174,14 @@ const float *SCULPT_vertex_color_get(SculptSession *ss, int index)
}
break;
case PBVH_BMESH:
+ case PBVH_TRIMESH:
case PBVH_GRIDS:
break;
}
return NULL;
}
-void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3])
+void SCULPT_vertex_normal_get(SculptSession *ss, SculptIdx index, float no[3])
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
@@ -185,6 +197,11 @@ void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3])
case PBVH_BMESH:
copy_v3_v3(no, BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->no);
break;
+ case PBVH_TRIMESH: {
+ TMVert *v = (TMVert *)index;
+ copy_v3_v3(no, v->no);
+ break;
+ }
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
const int grid_index = index / key->grid_area;
@@ -196,7 +213,7 @@ void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3])
}
}
-const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, int index)
+const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, SculptIdx index)
{
if (ss->persistent_base) {
return ss->persistent_base[index].co;
@@ -204,7 +221,7 @@ const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, int index)
return SCULPT_vertex_co_get(ss, index);
}
-const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, int index)
+const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, SculptIdx index)
{
/* Always grab active shape key if the sculpt happens on shapekey. */
if (ss->shapekey_active) {
@@ -221,10 +238,11 @@ const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, int index)
return SCULPT_vertex_co_get(ss, index);
}
-void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3])
+void SCULPT_vertex_limit_surface_get(SculptSession *ss, SculptIdx index, float r_co[3])
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
+ case PBVH_TRIMESH:
case PBVH_BMESH:
copy_v3_v3(r_co, SCULPT_vertex_co_get(ss, index));
break;
@@ -242,7 +260,7 @@ void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3]
}
}
-void SCULPT_vertex_persistent_normal_get(SculptSession *ss, int index, float no[3])
+void SCULPT_vertex_persistent_normal_get(SculptSession *ss, SculptIdx index, float no[3])
{
if (ss->persistent_base) {
copy_v3_v3(no, ss->persistent_base[index].no);
@@ -251,10 +269,11 @@ void SCULPT_vertex_persistent_normal_get(SculptSession *ss, int index, float no[
SCULPT_vertex_normal_get(ss, index, no);
}
-float SCULPT_vertex_mask_get(SculptSession *ss, int index)
+float SCULPT_vertex_mask_get(SculptSession *ss, SculptIdx index)
{
BMVert *v;
float *mask;
+
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
return ss->vmask[index];
@@ -262,6 +281,11 @@ float SCULPT_vertex_mask_get(SculptSession *ss, int index)
v = BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index);
mask = BM_ELEM_CD_GET_VOID_P(v, CustomData_get_offset(&ss->bm->vdata, CD_PAINT_MASK));
return *mask;
+ case PBVH_TRIMESH: {
+ TMVert *tv = (TMVert *)index;
+ mask = TM_ELEM_CD_GET_VOID_P(tv, CustomData_get_offset(&ss->tm->vdata, CD_PAINT_MASK));
+ return *mask;
+ }
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
const int grid_index = index / key->grid_area;
@@ -274,9 +298,9 @@ float SCULPT_vertex_mask_get(SculptSession *ss, int index)
return 0.0f;
}
-int SCULPT_active_vertex_get(SculptSession *ss)
+SculptIdx SCULPT_active_vertex_get(SculptSession *ss)
{
- if (ELEM(BKE_pbvh_type(ss->pbvh), PBVH_FACES, PBVH_BMESH, PBVH_GRIDS)) {
+ if (ELEM(BKE_pbvh_type(ss->pbvh), PBVH_FACES, PBVH_BMESH, PBVH_TRIMESH, PBVH_GRIDS)) {
return ss->active_vertex_index;
}
return 0;
@@ -323,13 +347,15 @@ int SCULPT_active_face_set_get(SculptSession *ss)
ss->active_grid_index);
return ss->face_sets[face_index];
}
+ case PBVH_TRIMESH:
case PBVH_BMESH:
return SCULPT_FACE_SET_NONE;
}
+
return SCULPT_FACE_SET_NONE;
}
-void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible)
+void SCULPT_vertex_visible_set(SculptSession *ss, SculptIdx index, bool visible)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
@@ -339,18 +365,27 @@ void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible)
case PBVH_BMESH:
BM_elem_flag_set(BM_vert_at_index(ss->bm, index), BM_ELEM_HIDDEN, !visible);
break;
+ case PBVH_TRIMESH: {
+ TMVert *v = (TMVert *)index;
+ TM_elem_flag_set(v, TM_ELEM_HIDDEN, !visible);
+ break;
+ }
case PBVH_GRIDS:
break;
}
}
-bool SCULPT_vertex_visible_get(SculptSession *ss, int index)
+bool SCULPT_vertex_visible_get(SculptSession *ss, SculptIdx index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
return !(ss->mvert[index].flag & ME_HIDE);
case PBVH_BMESH:
return !BM_elem_flag_test(BM_vert_at_index(ss->bm, index), BM_ELEM_HIDDEN);
+ case PBVH_TRIMESH: {
+ TMVert *v = (TMVert *)index;
+ return !TM_elem_flag_test(v, TM_ELEM_HIDDEN);
+ }
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
const int grid_index = index / key->grid_area;
@@ -380,6 +415,7 @@ void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visibl
}
}
break;
+ case PBVH_TRIMESH:
case PBVH_BMESH:
break;
}
@@ -394,6 +430,7 @@ void SCULPT_face_sets_visibility_invert(SculptSession *ss)
ss->face_sets[i] *= -1;
}
break;
+ case PBVH_TRIMESH:
case PBVH_BMESH:
break;
}
@@ -421,12 +458,13 @@ void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible)
}
}
break;
+ case PBVH_TRIMESH:
case PBVH_BMESH:
break;
}
}
-bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index)
+bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, SculptIdx index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
@@ -438,6 +476,8 @@ bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index)
}
return false;
}
+ case PBVH_TRIMESH:
+ return true;
case PBVH_BMESH:
return true;
case PBVH_GRIDS:
@@ -446,7 +486,7 @@ bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index)
return true;
}
-bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index)
+bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, SculptIdx index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
@@ -458,6 +498,7 @@ bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index)
}
return true;
}
+ case PBVH_TRIMESH:
case PBVH_BMESH:
return true;
case PBVH_GRIDS: {
@@ -470,7 +511,7 @@ bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index)
return true;
}
-void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set)
+void SCULPT_vertex_face_set_set(SculptSession *ss, SculptIdx index, int face_set)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
@@ -481,6 +522,7 @@ void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set)
}
}
} break;
+ case PBVH_TRIMESH:
case PBVH_BMESH:
break;
case PBVH_GRIDS: {
@@ -495,7 +537,7 @@ void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set)
}
}
-int SCULPT_vertex_face_set_get(SculptSession *ss, int index)
+int SCULPT_vertex_face_set_get(SculptSession *ss, SculptIdx index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
@@ -508,6 +550,7 @@ int SCULPT_vertex_face_set_get(SculptSession *ss, int index)
}
return face_set;
}
+ case PBVH_TRIMESH:
case PBVH_BMESH:
return 0;
case PBVH_GRIDS: {
@@ -520,7 +563,7 @@ int SCULPT_vertex_face_set_get(SculptSession *ss, int index)
return 0;
}
-bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set)
+bool SCULPT_vertex_has_face_set(SculptSession *ss, SculptIdx index, int face_set)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
@@ -532,6 +575,7 @@ bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set)
}
return false;
}
+ case PBVH_TRIMESH:
case PBVH_BMESH:
return true;
case PBVH_GRIDS: {
@@ -557,14 +601,15 @@ void SCULPT_visibility_sync_all_face_sets_to_vertices(Object *ob)
BKE_sculpt_sync_face_sets_visibility_to_base_mesh(mesh);
BKE_sculpt_sync_face_sets_visibility_to_grids(mesh, ss->subdiv_ccg);
break;
- }
+ } break;
+ case PBVH_TRIMESH:
case PBVH_BMESH:
break;
}
}
static void UNUSED_FUNCTION(sculpt_visibility_sync_vertex_to_face_sets)(SculptSession *ss,
- int index)
+ SculptIdx index)
{
MeshElemMap *vert_map = &ss->pmap[index];
const bool visible = SCULPT_vertex_visible_get(ss, index);
@@ -650,12 +695,13 @@ static bool sculpt_check_unique_face_set_for_edge_in_base_mesh(SculptSession *ss
return true;
}
-bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index)
+bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, SculptIdx index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
return sculpt_check_unique_face_set_in_base_mesh(ss, index);
}
+ case PBVH_TRIMESH:
case PBVH_BMESH:
return false;
case PBVH_GRIDS: {
@@ -695,6 +741,7 @@ int SCULPT_face_set_next_available_get(SculptSession *ss)
next_face_set++;
return next_face_set;
}
+ case PBVH_TRIMESH:
case PBVH_BMESH:
return 0;
}
@@ -705,7 +752,7 @@ int SCULPT_face_set_next_available_get(SculptSession *ss)
#define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256
-static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter, int neighbor_index)
+static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter, SculptIdx neighbor_index)
{
for (int i = 0; i < iter->size; i++) {
if (iter->neighbors[i] == neighbor_index) {
@@ -717,12 +764,12 @@ static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter, int neigh
iter->capacity += SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
if (iter->neighbors == iter->neighbors_fixed) {
- iter->neighbors = MEM_mallocN(iter->capacity * sizeof(int), "neighbor array");
- memcpy(iter->neighbors, iter->neighbors_fixed, sizeof(int) * iter->size);
+ iter->neighbors = MEM_mallocN(iter->capacity * sizeof(SculptIdx), "neighbor array");
+ memcpy(iter->neighbors, iter->neighbors_fixed, sizeof(SculptIdx) * iter->size);
}
else {
iter->neighbors = MEM_reallocN_id(
- iter->neighbors, iter->capacity * sizeof(int), "neighbor array");
+ iter->neighbors, iter->capacity * sizeof(SculptIdx), "neighbor array");
}
}
@@ -730,8 +777,34 @@ static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter, int neigh
iter->size++;
}
+static void sculpt_vertex_neighbors_get_trimesh(SculptSession *ss,
+ SculptIdx index,
+ SculptVertexNeighborIter *iter)
+{
+ TMVert *v = (TMVert *)index;
+
+ iter->size = 0;
+ iter->num_duplicates = 0;
+ iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
+ iter->neighbors = iter->neighbors_fixed;
+
+ TM_ITER_VERT_TRIEDGES (v, f, e) {
+ TMVert *adv_v[2];
+ TM_getOtherVerts(f, v, adv_v);
+
+ for (int i = 0; i < 2; i++) {
+ TMVert *v_other = adv_v[i];
+
+ if (v_other != (TMVert *)index) {
+ sculpt_vertex_neighbor_add(iter, (SculptIdx)v_other);
+ }
+ }
+ }
+ TM_ITER_VERT_TRIEDGES_END
+}
+
static void sculpt_vertex_neighbors_get_bmesh(SculptSession *ss,
- int index,
+ SculptIdx index,
SculptVertexNeighborIter *iter)
{
BMVert *v = BM_vert_at_index(ss->bm, index);
@@ -754,7 +827,7 @@ static void sculpt_vertex_neighbors_get_bmesh(SculptSession *ss,
}
static void sculpt_vertex_neighbors_get_faces(SculptSession *ss,
- int index,
+ SculptIdx index,
SculptVertexNeighborIter *iter)
{
MeshElemMap *vert_map = &ss->pmap[index];
@@ -784,7 +857,7 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss,
}
static void sculpt_vertex_neighbors_get_grids(SculptSession *ss,
- const int index,
+ const SculptIdx index,
const bool include_duplicates,
SculptVertexNeighborIter *iter)
{
@@ -826,7 +899,7 @@ static void sculpt_vertex_neighbors_get_grids(SculptSession *ss,
}
void SCULPT_vertex_neighbors_get(SculptSession *ss,
- const int index,
+ const SculptIdx index,
const bool include_duplicates,
SculptVertexNeighborIter *iter)
{
@@ -837,19 +910,23 @@ void SCULPT_vertex_neighbors_get(SculptSession *ss,
case PBVH_BMESH:
sculpt_vertex_neighbors_get_bmesh(ss, index, iter);
return;
+ case PBVH_TRIMESH:
+ sculpt_vertex_neighbors_get_trimesh(ss, index, iter);
+ return;
case PBVH_GRIDS:
sculpt_vertex_neighbors_get_grids(ss, index, include_duplicates, iter);
return;
}
}
-static bool sculpt_check_boundary_vertex_in_base_mesh(const SculptSession *ss, const int index)
+static bool sculpt_check_boundary_vertex_in_base_mesh(const SculptSession *ss,
+ const SculptIdx index)
{
BLI_assert(ss->vertex_info.boundary);
return BLI_BITMAP_TEST(ss->vertex_info.boundary, index);
}
-bool SCULPT_vertex_is_boundary(const SculptSession *ss, const int index)
+bool SCULPT_vertex_is_boundary(const SculptSession *ss, const SculptIdx index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
@@ -862,6 +939,10 @@ bool SCULPT_vertex_is_boundary(const SculptSession *ss, const int index)
BMVert *v = BM_vert_at_index(ss->bm, index);
return BM_vert_is_boundary(v);
}
+ case PBVH_TRIMESH: {
+ TMVert *v = (TMVert *)index;
+ return TM_vert_is_boundary(v);
+ }
case PBVH_GRIDS: {
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
@@ -941,7 +1022,7 @@ bool SCULPT_check_vertex_pivot_symmetry(const float vco[3], const float pco[3],
}
typedef struct NearestVertexTLSData {
- int nearest_vertex_index;
+ SculptIdx nearest_vertex_index;
float nearest_vertex_distance_squared;
} NearestVertexTLSData;
@@ -982,7 +1063,7 @@ static void nearest_vertex_get_reduce(const void *__restrict UNUSED(userdata),
}
}
-int SCULPT_nearest_vertex_get(
+SculptIdx SCULPT_nearest_vertex_get(
Sculpt *sd, Object *ob, const float co[3], float max_distance, bool use_original)
{
SculptSession *ss = ob->sculpt;
@@ -1056,23 +1137,28 @@ void SCULPT_floodfill_init(SculptSession *ss, SculptFloodFill *flood)
int vertex_count = SCULPT_vertex_count_get(ss);
SCULPT_vertex_random_access_ensure(ss);
- flood->queue = BLI_gsqueue_new(sizeof(int));
+ flood->queue = BLI_gsqueue_new(sizeof(SculptIdx));
flood->visited_vertices = BLI_BITMAP_NEW(vertex_count, "visited vertices");
}
-void SCULPT_floodfill_add_initial(SculptFloodFill *flood, int index)
+void SCULPT_floodfill_add_initial(SculptFloodFill *flood, SculptIdx index)
{
BLI_gsqueue_push(flood->queue, &index);
}
-void SCULPT_floodfill_add_initial_with_symmetry(
- Sculpt *sd, Object *ob, SculptSession *ss, SculptFloodFill *flood, int index, float radius)
+void SCULPT_floodfill_add_initial_with_symmetry(Sculpt *sd,
+ Object *ob,
+ SculptSession *ss,
+ SculptFloodFill *flood,
+ SculptIdx index,
+ float radius)
{
/* Add active vertex and symmetric vertices to the queue. */
const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
for (char i = 0; i <= symm; ++i) {
if (SCULPT_is_symmetry_iteration_valid(i, symm)) {
- int v = -1;
+ SculptIdx v = -1;
+
if (i == 0) {
v = index;
}
@@ -1113,11 +1199,14 @@ void SCULPT_floodfill_add_active(
}
}
-void SCULPT_floodfill_execute(
- SculptSession *ss,
- SculptFloodFill *flood,
- bool (*func)(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata),
- void *userdata)
+void SCULPT_floodfill_execute(SculptSession *ss,
+ SculptFloodFill *flood,
+ bool (*func)(SculptSession *ss,
+ SculptIdx from_v,
+ SculptIdx to_v,
+ bool is_duplicate,
+ void *userdata),
+ void *userdata)
{
while (!BLI_gsqueue_is_empty(flood->queue)) {
int from_v;
@@ -1200,7 +1289,7 @@ static bool sculpt_tool_is_proxy_used(const char sculpt_tool)
static bool sculpt_brush_use_topology_rake(const SculptSession *ss, const Brush *brush)
{
return SCULPT_TOOL_HAS_TOPOLOGY_RAKE(brush->sculpt_tool) &&
- (brush->topology_rake_factor > 0.0f) && (ss->bm != NULL);
+ (brush->topology_rake_factor > 0.0f) && (ss->tm != NULL || ss->bm != NULL);
}
/**
@@ -1247,11 +1336,15 @@ void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data, Object *ob, Scul
{
SculptSession *ss = ob->sculpt;
BMesh *bm = ss->bm;
+ TM_TriMesh *tm = ss->tm;
memset(data, 0, sizeof(*data));
data->unode = unode;
- if (bm) {
+ if (tm) {
+ data->tm_log = ss->tm_log;
+ }
+ else if (bm) {
data->bm_log = ss->bm_log;
}
else {
@@ -1279,7 +1372,10 @@ void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *
void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter *iter)
{
if (orig_data->unode->type == SCULPT_UNDO_COORDS) {
- if (orig_data->bm_log) {
+ if (orig_data->tm_log) {
+ TM_log_original_vert_data(orig_data->tm_log, iter->tm_vert, &orig_data->co, &orig_data->no);
+ }
+ else if (orig_data->bm_log) {
BM_log_original_vert_data(orig_data->bm_log, iter->bm_vert, &orig_data->co, &orig_data->no);
}
else {
@@ -1415,7 +1511,7 @@ static void sculpt_project_v3(const SculptProjectVector *spvc, const float vec[3
* Same goes for alt-key smoothing. */
bool SCULPT_stroke_is_dynamic_topology(const SculptSession *ss, const Brush *brush)
{
- return ((BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) &&
+ return ((BKE_pbvh_type(ss->pbvh) == PBVH_TRIMESH) &&
(!ss->cache || (!ss->cache->alt_smooth)) &&
@@ -1505,7 +1601,7 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
};
TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true && !ss->bm, totnode);
+ BKE_pbvh_parallel_range_settings(&settings, true && !(ss->tm || ss->bm), totnode);
BLI_task_parallel_range(0, totnode, &data, paint_mesh_restore_co_task_cb, &settings);
BKE_pbvh_node_color_buffer_free(ss->pbvh);
@@ -1643,6 +1739,9 @@ bool SCULPT_brush_test_sphere(SculptBrushTest *test, const float co[3])
bool SCULPT_brush_test_sphere_sq(SculptBrushTest *test, const float co[3])
{
+ if (!co) {
+ return false;
+ }
float distsq = len_squared_v3v3(co, test->location);
if (distsq <= test->radius_squared) {
@@ -1777,9 +1876,9 @@ static float frontface(const Brush *br,
#if 0
static bool sculpt_brush_test_cyl(SculptBrushTest *test,
- float co[3],
- float location[3],
- const float area_no[3])
+ float co[3],
+ float location[3],
+ const float area_no[3])
{
if (sculpt_brush_test_sphere_fast(test, co)) {
float t1[3], t2[3], t3[3], dist;
@@ -1948,6 +2047,8 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
area_test.radius_squared = test_radius * test_radius;
}
+ // TODO
+
/* When the mesh is edited we can't rely on original coords
* (original mesh may not even have verts in brush radius). */
if (use_original && data->has_bm_orco) {
@@ -2416,7 +2517,7 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
const short vno[3],
const float fno[3],
const float mask,
- const int vertex_index,
+ const SculptIdx vertex_index,
const int thread_id)
{
StrokeCache *cache = ss->cache;
@@ -2812,7 +2913,7 @@ typedef struct {
float depth;
bool original;
- int active_vertex_index;
+ SculptIdx active_vertex_index;
float *face_normal;
int active_face_grid_index;
@@ -2916,6 +3017,93 @@ static void bmesh_topology_rake(
}
}
+static void do_topology_rake_trimesh_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ const Brush *brush = data->brush;
+
+ float direction[3];
+ copy_v3_v3(direction, ss->cache->grab_delta_symmetry);
+
+ float tmp[3];
+ mul_v3_v3fl(
+ tmp, ss->cache->sculpt_normal_symm, dot_v3v3(ss->cache->sculpt_normal_symm, direction));
+ sub_v3_v3(direction, tmp);
+ normalize_v3(direction);
+
+ /* Cancel if there's no grab data. */
+ if (is_zero_v3(direction)) {
+ return;
+ }
+
+ const float bstrength = clamp_f(data->strength, 0.0f, 1.0f);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float fade =
+ bstrength *
+ SCULPT_brush_strength_factor(
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, vd.index, thread_id) *
+ ss->cache->pressure;
+
+ float avg[3], val[3];
+
+ SCULPT_trimesh_four_neighbor_average(avg, direction, vd.tm_vert);
+
+ sub_v3_v3v3(val, avg, vd.co);
+
+ madd_v3_v3v3fl(val, vd.co, val, fade);
+
+ SCULPT_clip(sd, ss, vd.co, val);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void trimesh_topology_rake(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, float bstrength)
+{
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ const float strength = clamp_f(bstrength, 0.0f, 1.0f);
+
+ /* Interactions increase both strength and quality. */
+ const int iterations = 3;
+
+ int iteration;
+ const int count = iterations * strength + 1;
+ const float factor = iterations * strength / count;
+
+ for (iteration = 0; iteration <= count; iteration++) {
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .strength = factor,
+ };
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+
+ BLI_task_parallel_range(0, totnode, &data, do_topology_rake_trimesh_task_cb_ex, &settings);
+ }
+}
+
static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
@@ -5548,6 +5736,7 @@ static void sculpt_topology_update(Sculpt *sd,
Brush *brush,
UnifiedPaintSettings *UNUSED(ups))
{
+ // return;
SculptSession *ss = ob->sculpt;
int n, totnode;
@@ -5584,6 +5773,11 @@ static void sculpt_topology_update(Sculpt *sd,
BKE_pbvh_node_mark_topology_update(nodes[n]);
BKE_pbvh_bmesh_node_save_orig(ss->bm, nodes[n]);
}
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_TRIMESH) {
+ BKE_pbvh_node_mark_topology_update(nodes[n]);
+ BKE_pbvh_trimesh_node_save_orig(ss->tm, nodes[n]);
+ }
}
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
@@ -5596,6 +5790,22 @@ static void sculpt_topology_update(Sculpt *sd,
(brush->falloff_shape != PAINT_FALLOFF_SHAPE_SPHERE));
}
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_TRIMESH) {
+ int symidx = ss->cache->mirror_symmetry_pass + (ss->cache->radial_symmetry_pass * 8);
+ if (symidx > 127) {
+ symidx = 127;
+ }
+
+ BKE_pbvh_trimesh_update_topology(ss->pbvh,
+ mode,
+ ss->cache->location,
+ ss->cache->view_normal,
+ ss->cache->radius,
+ (brush->flag & BRUSH_FRONTFACE) != 0,
+ (brush->falloff_shape != PAINT_FALLOFF_SHAPE_SPHERE),
+ symidx);
+ }
+
MEM_SAFE_FREE(nodes);
/* Update average stroke position. */
@@ -5718,7 +5928,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
/* Dynamic-topology does not support Face Sets data, so it can't store/restore it from undo. */
/* TODO(pablodp606): This check should be done in the undo code and not here, but the rest of
* the sculpt code is not checking for unsupported undo types that may return a null node. */
- if (BKE_pbvh_type(ss->pbvh) != PBVH_BMESH) {
+ if (!ELEM(BKE_pbvh_type(ss->pbvh), PBVH_TRIMESH, PBVH_BMESH)) {
SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_FACE_SETS);
}
@@ -5903,7 +6113,8 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
}
if (sculpt_brush_use_topology_rake(ss, brush)) {
- bmesh_topology_rake(sd, ob, nodes, totnode, brush->topology_rake_factor);
+ // bmesh_topology_rake(sd, ob, nodes, totnode, brush->topology_rake_factor);
+ trimesh_topology_rake(sd, ob, nodes, totnode, brush->topology_rake_factor);
}
/* The cloth brush adds the gravity as a regular force and it is processed in the solver. */
@@ -5991,6 +6202,9 @@ static void sculpt_combine_proxies_task_cb(void *__restrict userdata,
if (ss->bm) {
copy_v3_v3(val, BM_log_original_vert_co(ss->bm_log, vd.bm_vert));
}
+ else if (ss->tm) {
+ copy_v3_v3(val, TM_log_original_vert_co(ss->tm_log, vd.tm_vert));
+ }
else {
copy_v3_v3(val, orco[vd.i]);
}
@@ -7076,7 +7290,7 @@ static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin)
bool use_origco = false;
if (srd->original && srd->ss->cache) {
- if (BKE_pbvh_type(srd->ss->pbvh) == PBVH_BMESH) {
+ if (BKE_pbvh_type(srd->ss->pbvh), PBVH_TRIMESH) {
use_origco = true;
}
else {
@@ -7112,7 +7326,7 @@ static void sculpt_find_nearest_to_ray_cb(PBVHNode *node, void *data_v, float *t
bool use_origco = false;
if (srd->original && srd->ss->cache) {
- if (BKE_pbvh_type(srd->ss->pbvh) == PBVH_BMESH) {
+ if (BKE_pbvh_type(srd->ss->pbvh) == PBVH_TRIMESH) {
use_origco = true;
}
else {
@@ -7233,7 +7447,10 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
/* Update the active vertex of the SculptSession. */
ss->active_vertex_index = srd.active_vertex_index;
- SCULPT_vertex_random_access_ensure(ss);
+ if (BKE_pbvh_type(ss->pbvh) != PBVH_TRIMESH) {
+ SCULPT_vertex_random_access_ensure(ss);
+ }
+
copy_v3_v3(out->active_vertex_co, SCULPT_active_vertex_co_get(ss));
switch (BKE_pbvh_type(ss->pbvh)) {
@@ -7245,7 +7462,7 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
ss->active_face_index = 0;
ss->active_grid_index = srd.active_face_grid_index;
break;
- case PBVH_BMESH:
+ case PBVH_TRIMESH:
ss->active_face_index = 0;
ss->active_grid_index = 0;
break;
@@ -7265,6 +7482,7 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
float radius;
/* Update cursor data in SculptSession. */
+
invert_m4_m4(ob->imat, ob->obmat);
copy_m3_m4(mat, vc.rv3d->viewinv);
mul_m3_v3(mat, viewDir);
@@ -7333,11 +7551,6 @@ bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mouse[2])
depth = SCULPT_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original);
- if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
- BM_mesh_elem_table_ensure(ss->bm, BM_VERT);
- BM_mesh_elem_index_ensure(ss->bm, BM_VERT);
- }
-
bool hit = false;
{
SculptRaycastData srd;
@@ -7594,8 +7807,8 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up
BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateColor);
}
- if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
- BKE_pbvh_bmesh_after_stroke(ss->pbvh);
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_TRIMESH) {
+ BKE_pbvh_trimesh_after_stroke(ss->pbvh);
}
/* Optimization: if there is locked key and active modifiers present in */
@@ -7990,6 +8203,11 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *op)
}
switch (BKE_pbvh_type(pbvh)) {
+ case PBVH_TRIMESH:
+ // SCULPT_undo_push_begin("Dynamic topology symmetrize");
+ // SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE);
+
+ break;
case PBVH_BMESH:
/* Dyntopo Symmetrize. */
@@ -8420,11 +8638,12 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float
const int max_preview_vertices = SCULPT_vertex_count_get(ss) * 3 * 2;
if (ss->preview_vert_index_list == NULL) {
- ss->preview_vert_index_list = MEM_callocN(max_preview_vertices * sizeof(int), "preview lines");
+ ss->preview_vert_index_list = MEM_callocN(max_preview_vertices * sizeof(SculptIdx),
+ "preview lines");
}
- GSQueue *not_visited_vertices = BLI_gsqueue_new(sizeof(int));
- int active_v = SCULPT_active_vertex_get(ss);
+ GSQueue *not_visited_vertices = BLI_gsqueue_new(sizeof(SculptIdx));
+ SculptIdx active_v = SCULPT_active_vertex_get(ss);
BLI_gsqueue_push(not_visited_vertices, &active_v);
while (!BLI_gsqueue_is_empty(not_visited_vertices)) {
@@ -8433,7 +8652,7 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) {
if (totpoints + (ni.size * 2) < max_preview_vertices) {
- int to_v = ni.index;
+ SculptIdx to_v = ni.index;
ss->preview_vert_index_list[totpoints] = from_v;
totpoints++;
ss->preview_vert_index_list[totpoints] = to_v;
@@ -8592,7 +8811,7 @@ static int sculpt_sample_color_invoke(bContext *C,
Object *ob = CTX_data_active_object(C);
Brush *brush = BKE_paint_brush(&sd->paint);
SculptSession *ss = ob->sculpt;
- int active_vertex = SCULPT_active_vertex_get(ss);
+ SculptIdx active_vertex = SCULPT_active_vertex_get(ss);
const float *active_vertex_color = SCULPT_vertex_color_get(ss, active_vertex);
if (!active_vertex_color) {
return OPERATOR_CANCELLED;
@@ -8649,7 +8868,7 @@ enum {
SCULPT_TOPOLOGY_ID_DEFAULT,
};
-static int SCULPT_vertex_get_connected_component(SculptSession *ss, int index)
+static int SCULPT_vertex_get_connected_component(SculptSession *ss, SculptIdx index)
{
if (ss->vertex_info.connected_component) {
return ss->vertex_info.connected_component[index];
@@ -8661,7 +8880,7 @@ static void SCULPT_fake_neighbor_init(SculptSession *ss, const float max_dist)
{
const int totvert = SCULPT_vertex_count_get(ss);
ss->fake_neighbors.fake_neighbor_index = MEM_malloc_arrayN(
- totvert, sizeof(int), "fake neighbor");
+ totvert, sizeof(SculptIdx), "fake neighbor");
for (int i = 0; i < totvert; i++) {
ss->fake_neighbors.fake_neighbor_index[i] = FAKE_NEIGHBOR_NONE;
}
@@ -8669,7 +8888,7 @@ static void SCULPT_fake_neighbor_init(SculptSession *ss, const float max_dist)
ss->fake_neighbors.current_max_distance = max_dist;
}
-static void SCULPT_fake_neighbor_add(SculptSession *ss, int v_index_a, int v_index_b)
+static void SCULPT_fake_neighbor_add(SculptSession *ss, SculptIdx v_index_a, SculptIdx v_index_b)
{
if (ss->fake_neighbors.fake_neighbor_index[v_index_a] == FAKE_NEIGHBOR_NONE) {
ss->fake_neighbors.fake_neighbor_index[v_index_a] = v_index_b;
@@ -8683,9 +8902,9 @@ static void sculpt_pose_fake_neighbors_free(SculptSession *ss)
}
typedef struct NearestVertexFakeNeighborTLSData {
- int nearest_vertex_index;
+ SculptIdx nearest_vertex_index;
float nearest_vertex_distance_squared;
- int current_topology_id;
+ SculptIdx current_topology_id;
} NearestVertexFakeNeighborTLSData;
static void do_fake_neighbor_search_task_cb(void *__restrict userdata,
@@ -8699,7 +8918,7 @@ static void do_fake_neighbor_search_task_cb(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- int vd_topology_id = SCULPT_vertex_get_connected_component(ss, vd.index);
+ SculptIdx vd_topology_id = SCULPT_vertex_get_connected_component(ss, vd.index);
if (vd_topology_id != nvtd->current_topology_id &&
ss->fake_neighbors.fake_neighbor_index[vd.index] == FAKE_NEIGHBOR_NONE) {
float distance_squared = len_squared_v3v3(vd.co, data->nearest_vertex_search_co);
@@ -8729,7 +8948,10 @@ static void fake_neighbor_search_reduce(const void *__restrict UNUSED(userdata),
}
}
-static int SCULPT_fake_neighbor_search(Sculpt *sd, Object *ob, const int index, float max_distance)
+static SculptIdx SCULPT_fake_neighbor_search(Sculpt *sd,
+ Object *ob,
+ const SculptIdx index,
+ float max_distance)
{
SculptSession *ss = ob->sculpt;
PBVHNode **nodes = NULL;
@@ -8778,7 +9000,7 @@ typedef struct SculptTopologyIDFloodFillData {
} SculptTopologyIDFloodFillData;
static bool SCULPT_connected_components_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool UNUSED(is_duplicate), void *userdata)
+ SculptSession *ss, SculptIdx from_v, SculptIdx to_v, bool UNUSED(is_duplicate), void *userdata)
{
SculptTopologyIDFloodFillData *data = userdata;
ss->vertex_info.connected_component[from_v] = data->next_id;
@@ -8797,7 +9019,8 @@ static void sculpt_connected_components_ensure(Object *ob)
}
const int totvert = SCULPT_vertex_count_get(ss);
- ss->vertex_info.connected_component = MEM_malloc_arrayN(totvert, sizeof(int), "topology ID");
+ ss->vertex_info.connected_component = MEM_malloc_arrayN(
+ totvert, sizeof(SculptIdx), "topology ID");
for (int i = 0; i < totvert; i++) {
ss->vertex_info.connected_component[i] = SCULPT_TOPOLOGY_ID_NONE;
@@ -8864,12 +9087,12 @@ void SCULPT_fake_neighbors_ensure(Sculpt *sd, Object *ob, const float max_dist)
sculpt_connected_components_ensure(ob);
SCULPT_fake_neighbor_init(ss, max_dist);
- for (int i = 0; i < totvert; i++) {
- const int from_v = i;
+ for (SculptIdx i = 0; i < (SculptIdx)totvert; i++) {
+ const SculptIdx from_v = i;
/* This vertex does not have a fake neighbor yet, seach one for it. */
if (ss->fake_neighbors.fake_neighbor_index[from_v] == FAKE_NEIGHBOR_NONE) {
- const int to_v = SCULPT_fake_neighbor_search(sd, ob, from_v, max_dist);
+ const SculptIdx to_v = SCULPT_fake_neighbor_search(sd, ob, from_v, max_dist);
if (to_v != -1) {
/* Add the fake neighbor if available. */
SCULPT_fake_neighbor_add(ss, from_v, to_v);
@@ -8987,7 +9210,7 @@ static void do_mask_by_color_contiguous_update_nodes_cb(
}
static bool sculpt_mask_by_color_contiguous_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+ SculptSession *ss, SculptIdx from_v, SculptIdx to_v, bool is_duplicate, void *userdata)
{
MaskByColorContiguousFloodFillData *data = userdata;
const float *current_color = SCULPT_vertex_color_get(ss, to_v);
@@ -9005,7 +9228,7 @@ static bool sculpt_mask_by_color_contiguous_floodfill_cb(
}
static void sculpt_mask_by_color_contiguous(Object *object,
- const int vertex,
+ const SculptIdx vertex,
const float threshold,
const bool invert,
const bool preserve_mask)
@@ -9094,7 +9317,7 @@ static void do_mask_by_color_task_cb(void *__restrict userdata,
}
static void sculpt_mask_by_color_full_mesh(Object *object,
- const int vertex,
+ const SculptIdx vertex,
const float threshold,
const bool invert,
const bool preserve_mask)
@@ -9150,7 +9373,7 @@ static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEven
SCULPT_undo_push_begin("Mask by color");
- const int active_vertex = SCULPT_active_vertex_get(ss);
+ const SculptIdx active_vertex = SCULPT_active_vertex_get(ss);
const float threshold = RNA_float_get(op->ptr, "threshold");
const bool invert = RNA_boolean_get(op->ptr, "invert");
const bool preserve_mask = RNA_boolean_get(op->ptr, "preserve_previous_mask");
diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.c b/source/blender/editors/sculpt_paint/sculpt_automasking.c
index f2fc1bcb3c9..643baf45a75 100644
--- a/source/blender/editors/sculpt_paint/sculpt_automasking.c
+++ b/source/blender/editors/sculpt_paint/sculpt_automasking.c
@@ -127,7 +127,7 @@ static bool SCULPT_automasking_needs_factors_cache(const Sculpt *sd, const Brush
return false;
}
-float SCULPT_automasking_factor_get(AutomaskingCache *automasking, SculptSession *ss, int vert)
+float SCULPT_automasking_factor_get(AutomaskingCache *automasking, SculptSession *ss, SculptIdx vert)
{
if (!automasking) {
return 1.0f;
@@ -192,7 +192,7 @@ typedef struct AutomaskFloodFillData {
} AutomaskFloodFillData;
static bool automask_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool UNUSED(is_duplicate), void *userdata)
+ SculptSession *ss, SculptIdx from_v, SculptIdx to_v, bool UNUSED(is_duplicate), void *userdata)
{
AutomaskFloodFillData *data = userdata;
diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c
index ce8b63ce4f8..c017c36dce7 100644
--- a/source/blender/editors/sculpt_paint/sculpt_boundary.c
+++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c
@@ -54,6 +54,7 @@
#include "GPU_state.h"
#include "bmesh.h"
+#include "trimesh.h"
#include <math.h>
#include <stdlib.h>
@@ -62,15 +63,15 @@
#define BOUNDARY_STEPS_NONE -1
typedef struct BoundaryInitialVertexFloodFillData {
- int initial_vertex;
+ SculptIdx initial_vertex;
int boundary_initial_vertex_steps;
- int boundary_initial_vertex;
+ SculptIdx boundary_initial_vertex;
int *floodfill_steps;
float radius_sq;
} BoundaryInitialVertexFloodFillData;
static bool boundary_initial_vertex_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+ SculptSession *ss, SculptIdx from_v, SculptIdx to_v, bool is_duplicate, void *userdata)
{
BoundaryInitialVertexFloodFillData *data = userdata;
@@ -99,8 +100,8 @@ static bool boundary_initial_vertex_floodfill_cb(
/* From a vertex index anywhere in the mesh, returns the closest vertex in a mesh boundary inside
* the given radius, if it exists. */
-static int sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss,
- const int initial_vertex,
+static SculptIdx sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss,
+ const SculptIdx initial_vertex,
const float radius)
{
@@ -120,7 +121,7 @@ static int sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss,
};
fdata.floodfill_steps = MEM_calloc_arrayN(
- SCULPT_vertex_count_get(ss), sizeof(int), "floodfill steps");
+ SCULPT_vertex_count_get(ss), sizeof(SculptIdx), "floodfill steps");
SCULPT_floodfill_execute(ss, &flood, boundary_initial_vertex_floodfill_cb, &fdata);
SCULPT_floodfill_free(&flood);
@@ -135,7 +136,7 @@ static int sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss,
static int BOUNDARY_INDICES_BLOCK_SIZE = 300;
static void sculpt_boundary_index_add(SculptBoundary *boundary,
- const int new_index,
+ const SculptIdx new_index,
const float distance,
GSet *included_vertices)
{
@@ -151,11 +152,11 @@ static void sculpt_boundary_index_add(SculptBoundary *boundary,
if (boundary->num_vertices >= boundary->vertices_capacity) {
boundary->vertices_capacity += BOUNDARY_INDICES_BLOCK_SIZE;
boundary->vertices = MEM_reallocN_id(
- boundary->vertices, boundary->vertices_capacity * sizeof(int), "boundary indices");
+ boundary->vertices, boundary->vertices_capacity * sizeof(SculptIdx), "boundary indices");
}
};
-static void sculpt_boundary_preview_edge_add(SculptBoundary *boundary, const int v1, const int v2)
+static void sculpt_boundary_preview_edge_add(SculptBoundary *boundary, const SculptIdx v1, const SculptIdx v2)
{
boundary->edges[boundary->num_edges].v1 = v1;
@@ -175,7 +176,7 @@ static void sculpt_boundary_preview_edge_add(SculptBoundary *boundary, const int
* as well as to check if the initial vertex is valid.
*/
static bool sculpt_boundary_is_vertex_in_editable_boundary(SculptSession *ss,
- const int initial_vertex)
+ const SculptIdx initial_vertex)
{
if (!SCULPT_vertex_visible_get(ss, initial_vertex)) {
@@ -223,7 +224,7 @@ typedef struct BoundaryFloodFillData {
} BoundaryFloodFillData;
static bool boundary_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+ SculptSession *ss, SculptIdx from_v, SculptIdx to_v, bool is_duplicate, void *userdata)
{
BoundaryFloodFillData *data = userdata;
SculptBoundary *boundary = data->boundary;
@@ -245,12 +246,12 @@ static bool boundary_floodfill_cb(
static void sculpt_boundary_indices_init(SculptSession *ss,
SculptBoundary *boundary,
const bool init_boundary_distances,
- const int initial_boundary_index)
+ const SculptIdx initial_boundary_index)
{
const int totvert = SCULPT_vertex_count_get(ss);
boundary->vertices = MEM_malloc_arrayN(
- BOUNDARY_INDICES_BLOCK_SIZE, sizeof(int), "boundary indices");
+ BOUNDARY_INDICES_BLOCK_SIZE, sizeof(SculptIdx), "boundary indices");
if (init_boundary_distances) {
boundary->distance = MEM_calloc_arrayN(totvert, sizeof(float), "boundary distances");
}
@@ -302,7 +303,7 @@ static void sculpt_boundary_indices_init(SculptSession *ss,
*/
static void sculpt_boundary_edit_data_init(SculptSession *ss,
SculptBoundary *boundary,
- const int initial_vertex,
+ const SculptIdx initial_vertex,
const float radius)
{
const int totvert = SCULPT_vertex_count_get(ss);
@@ -317,8 +318,8 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss,
boundary->edit_info[i].num_propagation_steps = BOUNDARY_STEPS_NONE;
}
- GSQueue *current_iteration = BLI_gsqueue_new(sizeof(int));
- GSQueue *next_iteration = BLI_gsqueue_new(sizeof(int));
+ GSQueue *current_iteration = BLI_gsqueue_new(sizeof(SculptIdx));
+ GSQueue *next_iteration = BLI_gsqueue_new(sizeof(SculptIdx));
/* Initialized the first iteration with the vertices already in the boundary. This is propagation
* step 0. */
@@ -496,7 +497,7 @@ static void sculpt_boundary_falloff_factor_init(SculptSession *ss,
* return NULL if there is no boundary from the given vertex using the given radius. */
SculptBoundary *SCULPT_boundary_data_init(Object *object,
Brush *brush,
- const int initial_vertex,
+ const SculptIdx initial_vertex,
const float radius)
{
SculptSession *ss = object->sculpt;
@@ -508,7 +509,7 @@ SculptBoundary *SCULPT_boundary_data_init(Object *object,
SCULPT_vertex_random_access_ensure(ss);
SCULPT_boundary_info_ensure(object);
- const int boundary_initial_vertex = sculpt_boundary_get_closest_boundary_vertex(
+ const SculptIdx boundary_initial_vertex = sculpt_boundary_get_closest_boundary_vertex(
ss, initial_vertex, radius);
if (boundary_initial_vertex == BOUNDARY_VERTEX_NONE) {
@@ -877,7 +878,7 @@ void SCULPT_do_boundary_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totn
const int symm_area = ss->cache->mirror_symmetry_pass;
if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
- int initial_vertex;
+ SculptIdx initial_vertex;
if (ss->cache->mirror_symmetry_pass == 0) {
initial_vertex = SCULPT_active_vertex_get(ss);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c
index 591168fd3a2..f4e720f2bd6 100644
--- a/source/blender/editors/sculpt_paint/sculpt_cloth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c
@@ -98,6 +98,7 @@
#include "bmesh.h"
#include "bmesh_tools.h"
+#include "trimesh.h"
#include <math.h>
#include <stdlib.h>
diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
index 22bcbcc3bf1..525b10b3661 100644
--- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
@@ -72,6 +72,7 @@
#include "bmesh.h"
#include "bmesh_tools.h"
+#include "trimesh.h"
#include <math.h>
#include <stdlib.h>
@@ -110,6 +111,187 @@ void SCULPT_pbvh_clear(Object *ob)
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
+#ifdef WITH_TRIMESH
+void SCULPT_dyntopo_node_layers_add(SculptSession *ss)
+{
+ int cd_node_layer_index;
+
+ char layer_id[] = "_dyntopo_node_id";
+
+ cd_node_layer_index = CustomData_get_named_layer_index(&ss->tm->vdata, CD_PROP_INT32, layer_id);
+ if (cd_node_layer_index == -1) {
+ TM_data_layer_add_named(ss->tm, &ss->tm->vdata, CD_PROP_INT32, layer_id);
+ cd_node_layer_index = CustomData_get_named_layer_index(
+ &ss->tm->vdata, CD_PROP_INT32, layer_id);
+ }
+
+ ss->cd_vert_node_offset = CustomData_get_n_offset(
+ &ss->tm->vdata,
+ CD_PROP_INT32,
+ cd_node_layer_index - CustomData_get_layer_index(&ss->tm->vdata, CD_PROP_INT32));
+
+ ss->tm->vdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY;
+
+ cd_node_layer_index = CustomData_get_named_layer_index(&ss->tm->tdata, CD_PROP_INT32, layer_id);
+ if (cd_node_layer_index == -1) {
+ TM_data_layer_add_named(ss->tm, &ss->tm->tdata, CD_PROP_INT32, layer_id);
+ cd_node_layer_index = CustomData_get_named_layer_index(
+ &ss->tm->tdata, CD_PROP_INT32, layer_id);
+ }
+
+ ss->cd_face_node_offset = CustomData_get_n_offset(
+ &ss->tm->tdata,
+ CD_PROP_INT32,
+ cd_node_layer_index - CustomData_get_layer_index(&ss->tm->tdata, CD_PROP_INT32));
+
+ ss->tm->tdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY;
+}
+
+void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ Mesh *me = ob->data;
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me);
+
+ SCULPT_pbvh_clear(ob);
+
+ ss->bm_smooth_shading = (scene->toolsettings->sculpt->flags & SCULPT_DYNTOPO_SMOOTH_SHADING) !=
+ 0;
+
+ /* Dynamic topology doesn't ensure selection state is valid, so remove T36280. */
+ BKE_mesh_mselect_clear(me);
+
+ /* Create triangles-only BMesh. */
+ ss->tm = TMesh_new(6); // XXX set maxthread properly
+
+ TM_mesh_tm_from_me(ss->tm,
+ me,
+ (&(struct TriMeshFromMeshParams){
+ .calc_face_normal = true,
+ .use_shapekey = true,
+ .active_shapekey = ob->shapenr,
+ }));
+
+ // SCULPT_dynamic_topology_triangulate(ss->bm);
+ TM_data_layer_add(ss->tm, &ss->tm->vdata, CD_PAINT_MASK);
+ SCULPT_dyntopo_node_layers_add(ss);
+
+ /* Make sure the data for existing faces are initialized. */
+ if (me->totpoly != ss->tm->tottri) {
+ TM_mesh_normals_update(ss->tm);
+ }
+
+ /* Enable dynamic topology. */
+ me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
+
+ /* Enable logging for undo/redo. */
+ ss->tm_log = TM_log_new(ss->tm, CustomData_get_layer_index(&ss->tm->vdata, CD_PAINT_MASK));
+
+ /* Update dependency graph, so modifiers that depend on dyntopo being enabled
+ * are re-evaluated and the PBVH is re-created. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ BKE_scene_graph_update_tagged(depsgraph, bmain);
+}
+
+/* Free the sculpt BMesh and BMLog
+ *
+ * If 'unode' is given, the BMesh's data is copied out to the unode
+ * before the BMesh is deleted so that it can be restored from. */
+static void SCULPT_dynamic_topology_disable_ex(
+ Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob, SculptUndoNode *unode)
+{
+ SculptSession *ss = ob->sculpt;
+ Mesh *me = ob->data;
+
+ SCULPT_pbvh_clear(ob);
+
+ if (unode) {
+ /* Free all existing custom data. */
+ 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);
+
+ /* Copy over stored custom data. */
+ SculptUndoNodeGeometry *geometry = &unode->geometry_bmesh_enter;
+ me->totvert = geometry->totvert;
+ me->totloop = geometry->totloop;
+ me->totpoly = geometry->totpoly;
+ me->totedge = geometry->totedge;
+ me->totface = 0;
+ CustomData_copy(
+ &geometry->vdata, &me->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, geometry->totvert);
+ CustomData_copy(
+ &geometry->edata, &me->edata, CD_MASK_MESH.emask, CD_DUPLICATE, geometry->totedge);
+ CustomData_copy(
+ &geometry->ldata, &me->ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, geometry->totloop);
+ CustomData_copy(
+ &geometry->pdata, &me->pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, geometry->totpoly);
+
+ BKE_mesh_update_customdata_pointers(me, false);
+ }
+ else {
+ BKE_sculptsession_tm_to_me(ob, true);
+
+ /* Reset Face Sets as they are no longer valid. */
+ if (!CustomData_has_layer(&me->pdata, CD_SCULPT_FACE_SETS)) {
+ CustomData_add_layer(&me->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, NULL, me->totpoly);
+ }
+ ss->face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS);
+ for (int i = 0; i < me->totpoly; i++) {
+ ss->face_sets[i] = 1;
+ }
+ me->face_sets_color_default = 1;
+
+ /* Sync the visibility to vertices manually as the pmap is still not initialized. */
+ for (int i = 0; i < me->totvert; i++) {
+ me->mvert[i].flag &= ~ME_HIDE;
+ me->mvert[i].flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+
+ /* Clear data. */
+ me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
+
+ /* Typically valid but with global-undo they can be NULL, see: T36234. */
+ if (ss->bm) {
+ BM_mesh_free(ss->bm);
+ ss->bm = NULL;
+ }
+ if (ss->bm_log) {
+ BM_log_free(ss->bm_log);
+ ss->bm_log = NULL;
+ }
+
+ if (ss->tm) {
+ TMesh_free(ss->tm);
+ ss->tm = NULL;
+ }
+ if (ss->tm_log) {
+ TM_log_free(ss->tm_log);
+ ss->tm_log = NULL;
+ }
+
+ BKE_particlesystem_reset_all(ob);
+ BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_OUTDATED);
+
+ /* Update dependency graph, so modifiers that depend on dyntopo being enabled
+ * are re-evaluated and the PBVH is re-created. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ BKE_scene_graph_update_tagged(depsgraph, bmain);
+}
+
+void SCULPT_dynamic_topology_disable(bContext *C, SculptUndoNode *unode)
+{
+ Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ SCULPT_dynamic_topology_disable_ex(bmain, depsgraph, scene, ob, unode);
+}
+#else
+
void SCULPT_dyntopo_node_layers_add(SculptSession *ss)
{
int cd_node_layer_index;
@@ -280,6 +462,7 @@ void SCULPT_dynamic_topology_disable(bContext *C, SculptUndoNode *unode)
Object *ob = CTX_data_active_object(C);
SCULPT_dynamic_topology_disable_ex(bmain, depsgraph, scene, ob, unode);
}
+#endif
void sculpt_dynamic_topology_disable_with_undo(Main *bmain,
Depsgraph *depsgraph,
@@ -287,7 +470,7 @@ void sculpt_dynamic_topology_disable_with_undo(Main *bmain,
Object *ob)
{
SculptSession *ss = ob->sculpt;
- if (ss->bm != NULL) {
+ if (ss->tm != NULL || ss->bm != NULL) {
/* May be false in background mode. */
const bool use_undo = G.background ? (ED_undo_stack_get() != NULL) : true;
if (use_undo) {
@@ -307,7 +490,7 @@ static void sculpt_dynamic_topology_enable_with_undo(Main *bmain,
Object *ob)
{
SculptSession *ss = ob->sculpt;
- if (ss->bm == NULL) {
+ if (ss->tm == NULL || ss->bm != NULL) {
/* May be false in background mode. */
const bool use_undo = G.background ? (ED_undo_stack_get() != NULL) : true;
if (use_undo) {
@@ -331,7 +514,7 @@ static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(o
WM_cursor_wait(true);
- if (ss->bm) {
+ if (ss->tm) {
sculpt_dynamic_topology_disable_with_undo(bmain, depsgraph, scene, ob);
}
else {
@@ -381,9 +564,9 @@ enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob)
enum eDynTopoWarnFlag flag = 0;
- BLI_assert(ss->bm == NULL);
+ BLI_assert(ss->tm == NULL || ss->bm != NULL);
UNUSED_VARS_NDEBUG(ss);
-
+#if 0
for (int i = 0; i < CD_NUMTYPES; i++) {
if (!ELEM(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX)) {
if (CustomData_has_layer(&me->vdata, i)) {
@@ -397,7 +580,7 @@ enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob)
}
}
}
-
+#endif
{
VirtualModifierData virtualModifierData;
ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
@@ -426,7 +609,7 @@ static int sculpt_dynamic_topology_toggle_invoke(bContext *C,
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
- if (!ss->bm) {
+ if (!ss->tm || !ss->bm) {
Scene *scene = CTX_data_scene(C);
enum eDynTopoWarnFlag flag = SCULPT_dynamic_topology_check(scene, ob);
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c
index 152d23dfa5b..2ea9910c71b 100644
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.c
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c
@@ -67,6 +67,7 @@
#include "RNA_define.h"
#include "bmesh.h"
+#include "trimesh.h"
#include <math.h>
#include <stdlib.h>
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
index 07986bbb032..860c30bf442 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
@@ -63,6 +63,7 @@
#include "UI_interface.h"
#include "bmesh.h"
+#include "trimesh.h"
#include <math.h>
#include <stdlib.h>
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
index e764df78c88..5ef926a9179 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
@@ -59,6 +59,7 @@
#include "UI_interface.h"
#include "bmesh.h"
+#include "trimesh.h"
#include <math.h>
#include <stdlib.h>
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
index 349e492a496..f5fde67b4b3 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
@@ -60,6 +60,7 @@
#include "UI_interface.h"
#include "bmesh.h"
+#include "trimesh.h"
#include <math.h>
#include <stdlib.h>
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 916e7336c37..3da89eadd75 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -96,20 +96,20 @@ char SCULPT_mesh_symmetry_xyz_get(Object *object);
void SCULPT_vertex_random_access_ensure(struct SculptSession *ss);
int SCULPT_vertex_count_get(struct SculptSession *ss);
-const float *SCULPT_vertex_co_get(struct SculptSession *ss, int index);
-void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3]);
-float SCULPT_vertex_mask_get(struct SculptSession *ss, int index);
-const float *SCULPT_vertex_color_get(SculptSession *ss, int index);
+const float *SCULPT_vertex_co_get(struct SculptSession *ss, SculptIdx index);
+void SCULPT_vertex_normal_get(SculptSession *ss, SculptIdx index, float no[3]);
+float SCULPT_vertex_mask_get(struct SculptSession *ss, SculptIdx index);
+const float *SCULPT_vertex_color_get(SculptSession *ss, SculptIdx index);
-const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, int index);
-void SCULPT_vertex_persistent_normal_get(SculptSession *ss, int index, float no[3]);
+const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, SculptIdx index);
+void SCULPT_vertex_persistent_normal_get(SculptSession *ss, SculptIdx index, float no[3]);
/* Coordinates used for manipulating the base mesh when Grab Active Vertex is enabled. */
-const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, int index);
+const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, SculptIdx index);
/* Returns the info of the limit surface when Multires is available, otherwise it returns the
* current coordinate of the vertex. */
-void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3]);
+void SCULPT_vertex_limit_surface_get(SculptSession *ss, SculptIdx index, float r_co[3]);
/* Returns the pointer to the coordinates that should be edited from a brush tool iterator
* depending on the given deformation target. */
@@ -120,22 +120,23 @@ float *SCULPT_brush_deform_target_vertex_co_get(SculptSession *ss,
#define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256
typedef struct SculptVertexNeighborIter {
/* Storage */
- int *neighbors;
+ SculptIdx *neighbors;
int size;
int capacity;
- int neighbors_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY];
+ SculptIdx neighbors_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY];
+ int neighbors_nindex[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY];
/* Internal iterator. */
int num_duplicates;
int i;
/* Public */
- int index;
+ SculptIdx index;
bool is_duplicate;
} SculptVertexNeighborIter;
void SCULPT_vertex_neighbors_get(struct SculptSession *ss,
- const int index,
+ const SculptIdx index,
const bool include_duplicates,
SculptVertexNeighborIter *iter);
@@ -163,7 +164,7 @@ void SCULPT_vertex_neighbors_get(struct SculptSession *ss,
} \
((void)0)
-int SCULPT_active_vertex_get(SculptSession *ss);
+SculptIdx SCULPT_active_vertex_get(SculptSession *ss);
const float *SCULPT_active_vertex_co_get(SculptSession *ss);
void SCULPT_active_vertex_normal_get(SculptSession *ss, float normal[3]);
@@ -179,12 +180,12 @@ void SCULPT_fake_neighbors_free(struct Object *ob);
/* Vertex Info. */
void SCULPT_boundary_info_ensure(Object *object);
/* Boundary Info needs to be initialized in order to use this function. */
-bool SCULPT_vertex_is_boundary(const SculptSession *ss, const int index);
+bool SCULPT_vertex_is_boundary(const SculptSession *ss, const SculptIdx index);
/* Sculpt Visibility API */
-void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible);
-bool SCULPT_vertex_visible_get(SculptSession *ss, int index);
+void SCULPT_vertex_visible_set(SculptSession *ss, SculptIdx index, bool visible);
+bool SCULPT_vertex_visible_get(SculptSession *ss, SculptIdx index);
void SCULPT_visibility_sync_all_face_sets_to_vertices(struct Object *ob);
void SCULPT_visibility_sync_all_vertex_to_face_sets(struct SculptSession *ss);
@@ -192,17 +193,17 @@ void SCULPT_visibility_sync_all_vertex_to_face_sets(struct SculptSession *ss);
/* Face Sets API */
int SCULPT_active_face_set_get(SculptSession *ss);
-int SCULPT_vertex_face_set_get(SculptSession *ss, int index);
-void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set);
+int SCULPT_vertex_face_set_get(SculptSession *ss, SculptIdx index);
+void SCULPT_vertex_face_set_set(SculptSession *ss, SculptIdx index, int face_set);
-bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set);
-bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index);
+bool SCULPT_vertex_has_face_set(SculptSession *ss, SculptIdx index, int face_set);
+bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, SculptIdx index);
int SCULPT_face_set_next_available_get(SculptSession *ss);
void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visible);
-bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index);
-bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index);
+bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, SculptIdx index);
+bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, SculptIdx index);
void SCULPT_face_sets_visibility_invert(SculptSession *ss);
void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible);
@@ -211,9 +212,12 @@ bool SCULPT_stroke_is_main_symmetry_pass(struct StrokeCache *cache);
bool SCULPT_stroke_is_first_brush_step(struct StrokeCache *cache);
bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(struct StrokeCache *cache);
+struct TriMeshLog;
+
/* Sculpt Original Data */
typedef struct {
struct BMLog *bm_log;
+ struct TriMeshLog *tm_log;
struct SculptUndoNode *unode;
float (*coords)[3];
@@ -245,7 +249,7 @@ void SCULPT_calc_brush_plane(struct Sculpt *sd,
void SCULPT_calc_area_normal(
Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3]);
-int SCULPT_nearest_vertex_get(struct Sculpt *sd,
+SculptIdx SCULPT_nearest_vertex_get(struct Sculpt *sd,
struct Object *ob,
const float co[3],
float max_distance,
@@ -291,13 +295,13 @@ void SCULPT_floodfill_add_initial_with_symmetry(struct Sculpt *sd,
struct Object *ob,
struct SculptSession *ss,
SculptFloodFill *flood,
- int index,
+ SculptIdx index,
float radius);
-void SCULPT_floodfill_add_initial(SculptFloodFill *flood, int index);
+void SCULPT_floodfill_add_initial(SculptFloodFill *flood, SculptIdx index);
void SCULPT_floodfill_execute(
struct SculptSession *ss,
SculptFloodFill *flood,
- bool (*func)(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata),
+ bool (*func)(SculptSession *ss, SculptIdx from_v, SculptIdx to_v, bool is_duplicate, void *userdata),
void *userdata);
void SCULPT_floodfill_free(SculptFloodFill *flood);
@@ -332,7 +336,7 @@ void SCULPT_pbvh_clear(Object *ob);
/* Automasking. */
float SCULPT_automasking_factor_get(struct AutomaskingCache *automasking,
SculptSession *ss,
- int vert);
+ SculptIdx vert);
/* Returns the automasking cache depending on the active tool. Used for code that can run both for
* brushes and filter. */
@@ -455,7 +459,7 @@ void SCULPT_pose_ik_chain_free(struct SculptPoseIKChain *ik_chain);
/* Boundary Brush. */
struct SculptBoundary *SCULPT_boundary_data_init(Object *object,
Brush *brush,
- const int initial_vertex,
+ const SculptIdx initial_vertex,
const float radius);
void SCULPT_boundary_data_free(struct SculptBoundary *boundary);
void SCULPT_do_boundary_brush(struct Sculpt *sd,
@@ -488,12 +492,15 @@ void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
/* Smooth Brush. */
void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], struct BMVert *v);
-void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int index);
-float SCULPT_neighbor_mask_average(SculptSession *ss, int index);
-void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index);
+struct TMVert;
+void SCULPT_trimesh_four_neighbor_average(float avg[3], float direction[3], struct TMVert *v);
+
+void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], SculptIdx index);
+float SCULPT_neighbor_mask_average(SculptSession *ss, SculptIdx index);
+void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], SculptIdx index);
/* Mask the mesh boundaries smoothing only the mesh surface without using automasking. */
-void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3], int index);
+void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3], SculptIdx index);
void SCULPT_smooth(Sculpt *sd,
Object *ob,
@@ -509,13 +516,13 @@ void SCULPT_surface_smooth_laplacian_step(SculptSession *ss,
float *disp,
const float co[3],
float (*laplacian_disp)[3],
- const int v_index,
+ const SculptIdx v_index,
const float origco[3],
const float alpha);
void SCULPT_surface_smooth_displace_step(SculptSession *ss,
float *co,
float (*laplacian_disp)[3],
- const int v_index,
+ const SculptIdx v_index,
const float beta,
const float fade);
void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
@@ -726,7 +733,7 @@ typedef struct SculptThreadedTaskData {
bool mask_by_color_preserve_mask;
/* Index of the vertex that is going to be used as a reference for the colors. */
- int mask_by_color_vertex;
+ SculptIdx mask_by_color_vertex;
float *mask_by_color_floodfill;
int face_set;
@@ -803,7 +810,7 @@ float SCULPT_brush_strength_factor(struct SculptSession *ss,
const short vno[3],
const float fno[3],
const float mask,
- const int vertex_index,
+ const SculptIdx vertex_index,
const int thread_id);
/* Tilts a normal by the x and y tilt values using the view axis. */
diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
index 5a921383ac3..f574d24ce6f 100644
--- a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
+++ b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
@@ -64,6 +64,7 @@
#include "sculpt_intern.h"
#include "bmesh.h"
+#include "trimesh.h"
#include <math.h>
#include <stdlib.h>
@@ -116,7 +117,7 @@ static void sculpt_expand_task_cb(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL)
{
- int vi = vd.index;
+ SculptIdx vi = vd.index;
float final_mask = *vd.mask;
if (data->mask_expand_use_normals) {
if (ss->filter_cache->normal_factor[SCULPT_active_vertex_get(ss)] <
@@ -312,7 +313,7 @@ typedef struct MaskExpandFloodFillData {
} MaskExpandFloodFillData;
static bool mask_expand_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+ SculptSession *ss, SculptIdx from_v, SculptIdx to_v, bool is_duplicate, void *userdata)
{
MaskExpandFloodFillData *data = userdata;
@@ -393,7 +394,7 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
}
}
- ss->filter_cache->mask_update_it = MEM_callocN(sizeof(int) * vertex_count,
+ ss->filter_cache->mask_update_it = MEM_callocN(sizeof(SculptIdx) * vertex_count,
"mask update iteration");
if (use_normals) {
ss->filter_cache->normal_factor = MEM_callocN(sizeof(float) * vertex_count,
diff --git a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
index e47a94dff90..b2ca3bca1e4 100644
--- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
+++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
@@ -53,6 +53,7 @@
#include "GPU_state.h"
#include "bmesh.h"
+#include "trimesh.h"
#include <math.h>
#include <stdlib.h>
diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_color.c b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
index f0047448a8d..6af5eed29fe 100644
--- a/source/blender/editors/sculpt_paint/sculpt_paint_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
@@ -65,6 +65,7 @@
#include "IMB_imbuf.h"
#include "bmesh.h"
+#include "trimesh.h"
#include <math.h>
#include <stdlib.h>
diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c
index 4b318a05591..34db3d5e79b 100644
--- a/source/blender/editors/sculpt_paint/sculpt_pose.c
+++ b/source/blender/editors/sculpt_paint/sculpt_pose.c
@@ -48,6 +48,7 @@
#include "sculpt_intern.h"
#include "bmesh.h"
+#include "trimesh.h"
#include <math.h>
#include <stdlib.h>
@@ -384,7 +385,7 @@ typedef struct PoseFloodFillData {
int current_face_set;
int next_face_set;
int prev_face_set;
- int next_vertex;
+ SculptIdx next_vertex;
bool next_face_set_found;
@@ -406,7 +407,7 @@ typedef struct PoseFloodFillData {
int fallback_count;
/* Face Set FK mode. */
- int *floodfill_it;
+ SculptIdx *floodfill_it;
float *fk_weights;
int initial_face_set;
int masked_face_set_it;
@@ -415,7 +416,7 @@ typedef struct PoseFloodFillData {
} PoseFloodFillData;
static bool pose_topology_floodfill_cb(
- SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata)
+ SculptSession *ss, SculptIdx UNUSED(from_v), SculptIdx to_v, bool is_duplicate, void *userdata)
{
PoseFloodFillData *data = userdata;
const float *co = SCULPT_vertex_co_get(ss, to_v);
@@ -444,11 +445,11 @@ static bool pose_topology_floodfill_cb(
}
static bool pose_face_sets_floodfill_cb(
- SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata)
+ SculptSession *ss, SculptIdx UNUSED(from_v), SculptIdx to_v, bool is_duplicate, void *userdata)
{
PoseFloodFillData *data = userdata;
- const int index = to_v;
+ const SculptIdx index = to_v;
bool visit_next = false;
const float *co = SCULPT_vertex_co_get(ss, index);
@@ -683,7 +684,7 @@ static SculptPoseIKChain *pose_ik_chain_init_topology(Sculpt *sd,
float next_chain_segment_target[3];
int totvert = SCULPT_vertex_count_get(ss);
- int nearest_vertex_index = SCULPT_nearest_vertex_get(sd, ob, initial_location, FLT_MAX, true);
+ SculptIdx nearest_vertex_index = SCULPT_nearest_vertex_get(sd, ob, initial_location, FLT_MAX, true);
/* Init the buffers used to keep track of the changes in the pose factors as more segments are
* added to the IK chain. */
@@ -768,7 +769,7 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets(
int current_face_set = SCULPT_FACE_SET_NONE;
int prev_face_set = SCULPT_FACE_SET_NONE;
- int current_vertex = SCULPT_active_vertex_get(ss);
+ SculptIdx current_vertex = SCULPT_active_vertex_get(ss);
for (int s = 0; s < ik_chain->tot_segments; s++) {
@@ -824,7 +825,7 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets(
}
static bool pose_face_sets_fk_find_masked_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+ SculptSession *ss, SculptIdx from_v, SculptIdx to_v, bool is_duplicate, void *userdata)
{
PoseFloodFillData *data = userdata;
@@ -858,7 +859,7 @@ static bool pose_face_sets_fk_find_masked_floodfill_cb(
}
static bool pose_face_sets_fk_set_weights_floodfill_cb(
- SculptSession *ss, int UNUSED(from_v), int to_v, bool UNUSED(is_duplicate), void *userdata)
+ SculptSession *ss, SculptIdx UNUSED(from_v), SculptIdx to_v, bool UNUSED(is_duplicate), void *userdata)
{
PoseFloodFillData *data = userdata;
data->fk_weights[to_v] = 1.0f;
@@ -872,14 +873,14 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk(
SculptPoseIKChain *ik_chain = pose_ik_chain_new(1, totvert);
- const int active_vertex = SCULPT_active_vertex_get(ss);
- const int active_face_set = SCULPT_active_face_set_get(ss);
+ const SculptIdx active_vertex = SCULPT_active_vertex_get(ss);
+ const SculptIdx active_face_set = SCULPT_active_face_set_get(ss);
SculptFloodFill flood;
SCULPT_floodfill_init(ss, &flood);
SCULPT_floodfill_add_initial(&flood, active_vertex);
PoseFloodFillData fdata;
- fdata.floodfill_it = MEM_calloc_arrayN(totvert, sizeof(int), "floodfill iteration");
+ fdata.floodfill_it = MEM_calloc_arrayN(totvert, sizeof(SculptIdx), "floodfill iteration");
fdata.floodfill_it[active_vertex] = 1;
fdata.initial_face_set = active_face_set;
fdata.masked_face_set = SCULPT_FACE_SET_NONE;
diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c
index 87ee7480c92..dff5f225d5f 100644
--- a/source/blender/editors/sculpt_paint/sculpt_smooth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c
@@ -58,11 +58,17 @@
#include "RNA_define.h"
#include "bmesh.h"
+#include "trimesh.h"
+
+#ifdef PROXY_ADVANCED
+#include "BKE_DerivedMesh.h"
+#include "../../blenkernel/intern/pbvh_intern.h"
+#endif
#include <math.h>
#include <stdlib.h>
-void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3], int index)
+void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3], SculptIdx index)
{
float avg[3] = {0.0f, 0.0f, 0.0f};
int total = 0;
@@ -149,10 +155,57 @@ void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], BMVert
}
}
+/* For bmesh: Average surrounding verts based on an orthogonality measure.
+* Naturally converges to a quad-like structure. */
+void SCULPT_trimesh_four_neighbor_average(float avg[3], float direction[3], TMVert *v)
+{
+
+ float avg_co[3] = {0.0f, 0.0f, 0.0f};
+ float tot_co = 0.0f;
+
+ for (int i=0; i<v->edges.length; i++) {
+ TMEdge *e = v->edges.items[i];
+
+ if (TM_edge_is_boundary(e)) {
+ copy_v3_v3(avg, v->co);
+ return;
+ }
+
+ TMVert *v_other = (e->v1 == v) ? e->v2 : e->v1;
+ float vec[3];
+ sub_v3_v3v3(vec, v_other->co, v->co);
+ madd_v3_v3fl(vec, v->no, -dot_v3v3(vec, v->no));
+ normalize_v3(vec);
+
+ /* fac is a measure of how orthogonal or parallel the edge is
+ * relative to the direction. */
+ float fac = dot_v3v3(vec, direction);
+ fac = fac * fac - 0.5f;
+ fac *= fac;
+ madd_v3_v3fl(avg_co, v_other->co, fac);
+ tot_co += fac;
+ }
+
+ /* In case vert has no Edge s. */
+ if (tot_co > 0.0f) {
+ mul_v3_v3fl(avg, avg_co, 1.0f / tot_co);
+
+ /* Preserve volume. */
+ float vec[3];
+ sub_v3_v3(avg, v->co);
+ mul_v3_v3fl(vec, v->no, dot_v3v3(avg, v->no));
+ sub_v3_v3(avg, vec);
+ add_v3_v3(avg, v->co);
+ }
+ else {
+ zero_v3(avg);
+ }
+}
+
/* Generic functions for laplacian smoothing. These functions do not take boundary vertices into
* account. */
-void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int index)
+void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], SculptIdx index)
{
float avg[3] = {0.0f, 0.0f, 0.0f};
int total = 0;
@@ -172,7 +225,7 @@ void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int inde
}
}
-float SCULPT_neighbor_mask_average(SculptSession *ss, int index)
+float SCULPT_neighbor_mask_average(SculptSession *ss, SculptIdx index)
{
float avg = 0.0f;
int total = 0;
@@ -190,7 +243,7 @@ float SCULPT_neighbor_mask_average(SculptSession *ss, int index)
return SCULPT_vertex_mask_get(ss, index);
}
-void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index)
+void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], SculptIdx index)
{
float avg[4] = {0.0f, 0.0f, 0.0f, 0.0f};
int total = 0;
@@ -289,6 +342,96 @@ static void SCULPT_enhance_details_brush(Sculpt *sd,
BLI_task_parallel_range(0, totnode, &data, do_enhance_details_brush_task_cb_ex, &settings);
}
+
+#ifdef PROXY_ADVANCED
+static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ const Brush *brush = data->brush;
+ const bool smooth_mask = data->smooth_mask;
+ float bstrength = data->strength;
+
+ PBVHVertexIter vd;
+
+ CLAMP(bstrength, 0.0f, 1.0f);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ PBVHNode **nodes = data->nodes;
+ ProxyVertArray *p = &nodes[n]->proxyverts;
+
+ for (int i = 0; i < p->size; i++) {
+ float co[3] = {0.0f, 0.0f, 0.0f};
+ int ni = 0;
+
+# if 1
+ if (sculpt_brush_test_sq_fn(&test, p->co[i])) {
+ const float fade = bstrength * SCULPT_brush_strength_factor(
+ ss,
+ brush,
+ p->co[i],
+ sqrtf(test.dist),
+ p->no[i],
+ p->fno[i],
+ smooth_mask ? 0.0f : (p->mask ? p->mask[i] : 0.0f),
+ p->index[i],
+ thread_id);
+# else
+ if (1) {
+ const float fade = 1.0;
+# endif
+
+ while (/*ni < MAX_PROXY_NEIGHBORS &&*/ p->neighbors[i][ni].node >= 0) {
+ ProxyKey *key = p->neighbors[i] + ni;
+ PBVHNode *n2 = ss->pbvh->nodes + key->node;
+
+ // printf("%d %d %d %p\n", key->node, key->pindex, ss->pbvh->totnode, n2);
+ float *co2 = n2->proxyverts.co[key->pindex];
+
+ co[0] += co2[0];
+ co[1] += co2[1];
+ co[2] += co2[2];
+
+ //add_v3_v3(co, n2->proxyverts.co[key->pindex]);
+ ni++;
+ }
+
+ // printf("ni %d\n", ni);
+
+ if (ni > 2) {
+ float mul = 1.0 / (float) ni;
+
+ co[0] *= mul;
+ co[1] *= mul;
+ co[2] *= mul;
+ // mul_v3_fl(co, 1.0f / (float)ni);
+ }
+ else {
+ co[0] = p->co[i][0];
+ co[1] = p->co[i][1];
+ co[2] = p->co[i][2];
+ //copy_v3_v3(co, p->co[i]);
+
+ }
+
+ // printf("%f %f %f ", co[0], co[1], co[2]);
+ p->co[i][0] += (co[0] - p->co[i][0]) * fade;
+ p->co[i][1] += (co[1] - p->co[i][1]) * fade;
+ p->co[i][2] += (co[2] - p->co[i][2]) * fade;
+ //interp_v3_v3v3(p->co[i], p->co[i], co, fade);
+ }
+ }
+}
+
+#else
static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
@@ -343,6 +486,8 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
}
BKE_pbvh_vertex_iter_end;
}
+#endif
+
void SCULPT_smooth(Sculpt *sd,
Object *ob,
@@ -370,9 +515,18 @@ void SCULPT_smooth(Sculpt *sd,
return;
}
- SCULPT_vertex_random_access_ensure(ss);
+ if (type != PBVH_TRIMESH) {
+ SCULPT_vertex_random_access_ensure(ss);
+ }
+
SCULPT_boundary_info_ensure(ob);
+#ifdef PROXY_ADVANCED
+ int datamask = PV_CO | PV_NEIGHBORS | PV_NO | PV_INDEX | PV_MASK;
+ BKE_pbvh_ensure_proxyarrays(ss, ss->pbvh, datamask);
+
+ BKE_pbvh_load_proxyarrays(ss->pbvh, nodes, totnode, PV_CO | PV_NO | PV_MASK);
+#endif
for (iteration = 0; iteration <= count; iteration++) {
const float strength = (iteration != count) ? 1.0f : last;
@@ -388,6 +542,10 @@ void SCULPT_smooth(Sculpt *sd,
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_task_cb_ex, &settings);
+
+#ifdef PROXY_ADVANCED
+ BKE_pbvh_gather_proxyarray(ss->pbvh, nodes, totnode);
+#endif
}
}
@@ -411,7 +569,7 @@ void SCULPT_surface_smooth_laplacian_step(SculptSession *ss,
float *disp,
const float co[3],
float (*laplacian_disp)[3],
- const int v_index,
+ const SculptIdx v_index,
const float origco[3],
const float alpha)
{
@@ -430,7 +588,7 @@ void SCULPT_surface_smooth_laplacian_step(SculptSession *ss,
void SCULPT_surface_smooth_displace_step(SculptSession *ss,
float *co,
float (*laplacian_disp)[3],
- const int v_index,
+ const SculptIdx v_index,
const float beta,
const float fade)
{
diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c
index 479f70b5ff1..11992fab862 100644
--- a/source/blender/editors/sculpt_paint/sculpt_transform.c
+++ b/source/blender/editors/sculpt_paint/sculpt_transform.c
@@ -56,6 +56,7 @@
#include "RNA_define.h"
#include "bmesh.h"
+#include "trimesh.h"
#include <math.h>
#include <stdlib.h>
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index fa9eb43891c..14a21e104dd 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -68,6 +68,7 @@
#include "ED_undo.h"
#include "bmesh.h"
+#include "trimesh.h"
#include "sculpt_intern.h"
/* Implementation of undo system for objects in sculpt mode.
@@ -402,6 +403,48 @@ static bool sculpt_undo_restore_face_sets(bContext *C, SculptUndoNode *unode)
return false;
}
+
+static void sculpt_undo_trimesh_restore_generic_task_cb(
+ void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ PBVHNode **nodes = userdata;
+
+ BKE_pbvh_node_mark_redraw(nodes[n]);
+}
+
+static void sculpt_undo_trimesh_restore_generic(SculptUndoNode *unode, Object *ob, SculptSession *ss)
+{
+ //XXX
+ return;
+ if (unode->applied) {
+ BM_log_undo(ss->bm, ss->bm_log);
+ unode->applied = false;
+ }
+ else {
+ BM_log_redo(ss->bm, ss->bm_log);
+ unode->applied = true;
+ }
+
+ if (unode->type == SCULPT_UNDO_MASK) {
+ int totnode;
+ PBVHNode **nodes;
+
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(
+ 0, totnode, nodes, sculpt_undo_trimesh_restore_generic_task_cb, &settings);
+
+ if (nodes) {
+ MEM_freeN(nodes);
+ }
+ }
+ else {
+ SCULPT_pbvh_clear(ob);
+ }
+}
+
static void sculpt_undo_bmesh_restore_generic_task_cb(
void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
{
@@ -412,6 +455,8 @@ static void sculpt_undo_bmesh_restore_generic_task_cb(
static void sculpt_undo_bmesh_restore_generic(SculptUndoNode *unode, Object *ob, SculptSession *ss)
{
+ //XXX
+ return;
if (unode->applied) {
BM_log_undo(ss->bm, ss->bm_log);
unode->applied = false;
@@ -501,6 +546,67 @@ static void sculpt_undo_bmesh_restore_end(bContext *C,
}
}
+/* Create empty sculpt BMesh and enable logging. */
+static void sculpt_undo_trimesh_enable(Object *ob, SculptUndoNode *unode)
+{
+#if 0
+ SculptSession *ss = ob->sculpt;
+ Mesh *me = ob->data;
+ SCULPT_pbvh_clear(ob);
+
+ /* Create empty BMesh and enable logging. */
+ ss->bm = BM_mesh_create(&bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){
+ .use_toolflags = false,
+ }));
+ BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
+ SCULPT_dyntopo_node_layers_add(ss);
+ me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
+
+ /* Restore the BMLog using saved entries. */
+ ss->bm_log = BM_log_from_existing_entries_create(ss->bm, unode->bm_entry);
+#endif
+}
+
+static void sculpt_undo_trimesh_restore_begin(bContext *C,
+ SculptUndoNode *unode,
+ Object *ob,
+ SculptSession *ss)
+{
+ if (unode->applied) {
+ SCULPT_dynamic_topology_disable(C, unode);
+ unode->applied = false;
+ }
+ else {
+ sculpt_undo_trimesh_enable(ob, unode);
+
+ /* Restore the mesh from the first log entry. */
+ //XXX BM_log_redo(ss->bm, ss->bm_log);
+
+ unode->applied = true;
+ }
+}
+
+static void sculpt_undo_trimesh_restore_end(bContext *C,
+ SculptUndoNode *unode,
+ Object *ob,
+ SculptSession *ss)
+{
+ if (unode->applied) {
+ sculpt_undo_trimesh_enable(ob, unode);
+
+ /* Restore the mesh from the last log entry. */
+ //XXX BM_log_undo(ss->bm, ss->bm_log);
+
+ unode->applied = false;
+ }
+ else {
+ /* Disable dynamic topology sculpting. */
+ SCULPT_dynamic_topology_disable(C, NULL);
+ unode->applied = true;
+ }
+}
+
static void sculpt_undo_geometry_store_data(SculptUndoNodeGeometry *geometry, Object *object)
{
Mesh *mesh = object->data;
@@ -609,6 +715,34 @@ static int sculpt_undo_bmesh_restore(bContext *C,
return false;
}
+/* Handle all dynamic-topology updates
+*
+* Returns true if this was a dynamic-topology undo step, otherwise
+* returns false to indicate the non-dyntopo code should run. */
+static int sculpt_undo_trimesh_restore(bContext *C,
+ SculptUndoNode *unode,
+ Object *ob,
+ SculptSession *ss)
+{
+ switch (unode->type) {
+ case SCULPT_UNDO_DYNTOPO_BEGIN:
+ sculpt_undo_trimesh_restore_begin(C, unode, ob, ss);
+ return true;
+
+ case SCULPT_UNDO_DYNTOPO_END:
+ sculpt_undo_trimesh_restore_end(C, unode, ob, ss);
+ return true;
+ default:
+ if (ss->bm_log) {
+ sculpt_undo_trimesh_restore_generic(unode, ob, ss);
+ return true;
+ }
+ break;
+ }
+
+ return false;
+}
+
static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase *lb)
{
Scene *scene = CTX_data_scene(C);
@@ -674,7 +808,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, need_mask, false);
}
- if (sculpt_undo_bmesh_restore(C, lb->first, ob, ss)) {
+ if (sculpt_undo_trimesh_restore(C, lb->first, ob, ss)) {
return;
}
}
@@ -1243,6 +1377,97 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt
return unode;
}
+static SculptUndoNode *sculpt_undo_trimesh_push(Object *ob, PBVHNode *node, SculptUndoType type)
+{
+ UndoSculpt *usculpt = sculpt_undo_get_nodes();
+ SculptSession *ss = ob->sculpt;
+ PBVHVertexIter vd;
+
+ SculptUndoNode *unode = usculpt->nodes.first;
+ if (unode == NULL) {
+ unode = MEM_callocN(sizeof(*unode), __func__);
+ BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname));
+ unode->type = type;
+ unode->applied = true;
+ BLI_addtail(&usculpt->nodes, unode);
+ }
+
+ return unode;
+#if 1
+
+ if (unode == NULL) {
+ unode = MEM_callocN(sizeof(*unode), __func__);
+
+ BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname));
+ unode->type = type;
+ unode->applied = true;
+
+ if (type == SCULPT_UNDO_DYNTOPO_END) {
+ unode->bm_entry = BM_log_entry_add(ss->bm_log);
+ BM_log_before_all_removed(ss->bm, ss->bm_log);
+ }
+ else if (type == SCULPT_UNDO_DYNTOPO_BEGIN) {
+ /* Store a copy of the mesh's current vertices, loops, and
+ * polys. A full copy like this is needed because entering
+ * dynamic-topology immediately does topological edits
+ * (converting polys to triangles) that the BMLog can't
+ * fully restore from. */
+ SculptUndoNodeGeometry *geometry = &unode->geometry_bmesh_enter;
+ sculpt_undo_geometry_store_data(geometry, ob);
+
+ unode->bm_entry = BM_log_entry_add(ss->bm_log);
+ BM_log_all_added(ss->bm, ss->bm_log);
+ }
+ else {
+ unode->bm_entry = BM_log_entry_add(ss->bm_log);
+ }
+
+ BLI_addtail(&usculpt->nodes, unode);
+ }
+
+ if (node) {
+ switch (type) {
+ case SCULPT_UNDO_COORDS:
+ case SCULPT_UNDO_MASK:
+ /* Before any vertex values get modified, ensure their
+ * original positions are logged. */
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL)
+ {
+ BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset);
+ }
+ BKE_pbvh_vertex_iter_end;
+ break;
+
+ case SCULPT_UNDO_HIDDEN: {
+ GSetIterator gs_iter;
+ GSet *faces = BKE_pbvh_bmesh_node_faces(node);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL)
+ {
+ BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset);
+ }
+ BKE_pbvh_vertex_iter_end;
+
+ GSET_ITER (gs_iter, faces) {
+ BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+ BM_log_face_modified(ss->bm_log, f);
+ }
+ break;
+ }
+
+ case SCULPT_UNDO_DYNTOPO_BEGIN:
+ case SCULPT_UNDO_DYNTOPO_END:
+ case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
+ case SCULPT_UNDO_GEOMETRY:
+ case SCULPT_UNDO_FACE_SETS:
+ case SCULPT_UNDO_COLOR:
+ break;
+ }
+ }
+
+ return unode;
+#endif
+}
+
SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType type)
{
SculptSession *ss = ob->sculpt;
@@ -1253,10 +1478,10 @@ SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType
ss->needs_flush_to_id = 1;
- if (ss->bm || ELEM(type, SCULPT_UNDO_DYNTOPO_BEGIN, SCULPT_UNDO_DYNTOPO_END)) {
+ if (ss->tm || ELEM(type, SCULPT_UNDO_DYNTOPO_BEGIN, SCULPT_UNDO_DYNTOPO_END)) {
/* Dynamic topology stores only one undo node per stroke,
* regardless of the number of PBVH nodes modified. */
- unode = sculpt_undo_bmesh_push(ob, node, type);
+ unode = sculpt_undo_trimesh_push(ob, node, type);
BLI_thread_unlock(LOCK_CUSTOM1);
return unode;
}
diff --git a/source/blender/editors/space_info/CMakeLists.txt b/source/blender/editors/space_info/CMakeLists.txt
index b6df07eec4e..3102ac358a7 100644
--- a/source/blender/editors/space_info/CMakeLists.txt
+++ b/source/blender/editors/space_info/CMakeLists.txt
@@ -25,6 +25,7 @@ set(INC
../../bmesh
../../depsgraph
../../gpu
+ ../../trimesh
../../imbuf
../../makesdna
../../makesrna
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index b6eca8666a6..eff9736e556 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -66,6 +66,8 @@
#include "GPU_capabilities.h"
+#include "trimesh.h"
+
#define MAX_INFO_NUM_LEN 16
typedef struct SceneStats {
@@ -352,13 +354,13 @@ static void stats_object_pose(Object *ob, SceneStats *stats)
static void stats_object_sculpt_dynamic_topology(Object *ob, SceneStats *stats)
{
- stats->totvert = ob->sculpt->bm->totvert;
- stats->tottri = ob->sculpt->bm->totface;
+ stats->totvert = ob->sculpt->tm->totvert;
+ stats->tottri = ob->sculpt->tm->tottri;
}
static bool stats_is_object_dynamic_topology_sculpt(Object *ob, const eObjectMode object_mode)
{
- return (ob && (object_mode & OB_MODE_SCULPT) && ob->sculpt && ob->sculpt->bm);
+ return (ob && (object_mode & OB_MODE_SCULPT) && ob->sculpt && ob->sculpt->tm);
}
/* Statistics displayed in info header. Called regularly on scene changes. */
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 482e4086452..89db180f6ac 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -33,6 +33,7 @@ set(INC
../blenkernel
../blenlib
../bmesh
+ ../trimesh
../draw
../imbuf
../makesdna
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index b770bde65fc..69d1248e1ff 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -61,9 +61,11 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const struct MPoly *mpoly,
GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, unsigned int **grid_hidden);
GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading);
+GPU_PBVH_Buffers *GPU_pbvh_trimesh_buffers_build(bool smooth_shading);
/* Free part of data for update. Not thread safe, must run in OpenGL main thread. */
void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers);
+void GPU_pbvh_trimesh_buffers_update_free(GPU_PBVH_Buffers *buffers);
void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers,
const struct DMFlagMat *grid_flag_mats,
const int *grid_indices);
@@ -92,6 +94,14 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
struct GSet *bm_other_verts,
const int update_flags);
+struct TM_TriMesh;
+void GPU_pbvh_trimesh_buffers_update(GPU_PBVH_Buffers *buffers,
+ struct TM_TriMesh *bm,
+ struct GSet *bm_faces,
+ struct TMElemSet *bm_unique_verts,
+ struct TMElemSet *bm_other_verts,
+ const int update_flags, const int cd_vert_node_offset);
+
void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
struct SubdivCCG *subdiv_ccg,
struct CCGElem **grids,
diff --git a/source/blender/gpu/GPU_vertex_buffer.h b/source/blender/gpu/GPU_vertex_buffer.h
index eeaebd3fae5..93a77a2095a 100644
--- a/source/blender/gpu/GPU_vertex_buffer.h
+++ b/source/blender/gpu/GPU_vertex_buffer.h
@@ -118,7 +118,6 @@ GPU_INLINE void *GPU_vertbuf_raw_step(GPUVertBufRaw *a)
{
unsigned char *data = a->data;
a->data += a->stride;
- BLI_assert(data < a->_data_end);
return (void *)data;
}
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 13d0139e406..9ca965373f4 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -53,6 +53,7 @@
#include "gpu_private.h"
#include "bmesh.h"
+#include "trimesh.h"
/* XXX: the rest of the code in this file is used for optimized PBVH
* drawing and doesn't interact at all with the buffer code above */
@@ -84,7 +85,7 @@ struct GPU_PBVH_Buffers {
const int *grid_indices;
int totgrid;
- bool use_bmesh;
+ bool use_bmesh, use_trimesh;
bool clear_bmesh_on_flush;
uint tot_tri, tot_quad;
@@ -121,7 +122,7 @@ void gpu_pbvh_init()
g_vbo_id.msk = GPU_vertformat_attr_add(
&g_vbo_id.format, "msk", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
g_vbo_id.col = GPU_vertformat_attr_add(
- &g_vbo_id.format, "ac", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ &g_vbo_id.format, "c", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
g_vbo_id.fset = GPU_vertformat_attr_add(
&g_vbo_id.format, "fset", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
}
@@ -824,6 +825,111 @@ static void gpu_bmesh_vert_to_buffer_copy(BMVert *v,
GPU_vertbuf_attr_set(vert_buf, g_vbo_id.fset, v_index, &face_set);
}
+/* Output a BMVert into a VertexBufferFormat array at v_index. */
+static void gpu_trimesh_vert_to_buffer_copy(TMVert *v,
+ GPUVertBuf *vert_buf,
+ int v_index,
+ const float fno[3],
+ const float *fmask,
+ const int cd_vert_mask_offset,
+ const int cd_vert_node_offset,
+ const bool show_mask,
+ const bool show_vcol,
+ bool *empty_mask,
+ int cd_vcol_offset)
+{
+ /* Vertex should always be visible if it's used by a visible face. */
+ BLI_assert(!TM_elem_flag_test(v, TM_ELEM_HIDDEN));
+
+ /* Set coord, normal, and mask */
+ GPU_vertbuf_attr_set(vert_buf, g_vbo_id.pos, v_index, v->co);
+
+ short no_short[3];
+ normal_float_to_short_v3(no_short, fno ? fno : v->no);
+ GPU_vertbuf_attr_set(vert_buf, g_vbo_id.nor, v_index, no_short);
+
+ if (show_mask) {
+ float effective_mask = fmask ? *fmask : TM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset);
+ // int ni = TM_ELEM_CD_GET_INT(v, cd_vert_node_offset);
+ // float effective_mask = (float)(ni % 64) / 64.0f;
+
+ uchar cmask = (uchar)(effective_mask * 255);
+ GPU_vertbuf_attr_set(vert_buf, g_vbo_id.msk, v_index, &cmask);
+ *empty_mask = *empty_mask && (cmask == 0);
+ }
+
+ if (show_vcol && cd_vcol_offset >= 0) {
+ ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
+ int col[4] = {0, 0, 0, 0};
+ int tot = 0;
+
+ for (int i = 0; i < v->edges.length; i++) {
+ TMEdge *e = v->edges.items[i];
+
+ for (int j = 0; j < e->tris.length; j++) {
+ TMFace *t = e->tris.items[j];
+
+ TMLoopData *l = TM_GET_TRI_LOOP_EDGE(t, e);
+ MLoopCol *ml = TM_ELEM_CD_GET_VOID_P(l, cd_vcol_offset);
+
+ col[0] += ml->r;
+ col[1] += ml->g;
+ col[2] += ml->b;
+ col[3] += ml->a;
+ tot++;
+ }
+ }
+
+ if (tot) {
+ col[0] /= tot;
+ col[1] /= tot;
+ col[2] /= tot;
+ col[3] /= tot;
+
+ vcol[0] = (ushort)(col[0] * 257);
+ vcol[1] = (ushort)(col[1] * 257);
+ vcol[2] = (ushort)(col[2] * 257);
+ vcol[3] = (ushort)(col[3] * 257);
+ //printf("%d %d %d %d %d\n", vcol[0], vcol[1], vcol[2], vcol[3], tot);
+ }
+ //const ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
+ GPU_vertbuf_attr_set(vert_buf, g_vbo_id.col, v_index, vcol);
+ }
+ else if (show_vcol) {
+ const ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
+ GPU_vertbuf_attr_set(vert_buf, g_vbo_id.col, v_index, vcol);
+ }
+
+ /* Add default face sets color to avoid artifacts. */
+
+ const uchar face_set[3] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
+
+ GPU_vertbuf_attr_set(vert_buf, g_vbo_id.fset, v_index, face_set);
+}
+
+/* Return the total number of vertices that don't have BM_ELEM_HIDDEN set */
+static int gpu_trimesh_vert_visible_count(TMElemSet *bm_unique_verts, TMElemSet *bm_other_verts)
+{
+ int totvert = 0;
+ TMVert *v;
+
+ TMS_ITER (v, bm_unique_verts) {
+ if (!TM_elem_flag_test(v, TM_ELEM_HIDDEN)) {
+ totvert++;
+ }
+ }
+ TMS_ITER_END
+
+ TMS_ITER (v, bm_other_verts) {
+ if (!TM_elem_flag_test(v, TM_ELEM_HIDDEN)) {
+ totvert++;
+ }
+ }
+ TMS_ITER_END
+
+ return totvert;
+}
+
/* Return the total number of vertices that don't have BM_ELEM_HIDDEN set */
static int gpu_bmesh_vert_visible_count(GSet *bm_unique_verts, GSet *bm_other_verts)
{
@@ -863,6 +969,23 @@ static int gpu_bmesh_face_visible_count(GSet *bm_faces)
return totface;
}
+/* Return the total number of visible faces */
+static int gpu_trimesh_face_visible_count(GSet *bm_faces)
+{
+ GSetIterator gh_iter;
+ int totface = 0;
+
+ GSET_ITER (gh_iter, bm_faces) {
+ TMFace *f = BLI_gsetIterator_getKey(&gh_iter);
+
+ if (!TM_elem_flag_test(f, TM_ELEM_HIDDEN)) {
+ totface++;
+ }
+ }
+
+ return totface;
+}
+
void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers)
{
if (buffers->smooth) {
@@ -878,6 +1001,21 @@ void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers)
}
}
+void GPU_pbvh_trimesh_buffers_update_free(GPU_PBVH_Buffers *buffers)
+{
+ if (buffers->smooth) {
+ /* Smooth needs to recreate index buffer, so we have to invalidate the batch. */
+ GPU_BATCH_DISCARD_SAFE(buffers->triangles);
+ GPU_BATCH_DISCARD_SAFE(buffers->lines);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
+ }
+ else {
+ GPU_BATCH_DISCARD_SAFE(buffers->lines);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf);
+ }
+}
+
/* Creates a vertex buffer (coordinate, normal, color) and, if smooth
* shading, an element index buffer.
* Threaded - do not call any functions that use OpenGL calls! */
@@ -1042,6 +1180,178 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS);
}
+/* Creates a vertex buffer (coordinate, normal, color) and, if smooth
+ * shading, an element index buffer.
+ * Threaded - do not call any functions that use OpenGL calls! */
+void GPU_pbvh_trimesh_buffers_update(GPU_PBVH_Buffers *buffers,
+ TM_TriMesh *bm,
+ GSet *tm_faces,
+ TMElemSet *bm_unique_verts,
+ TMElemSet *bm_other_verts,
+ const int update_flags,
+ const int cd_vert_node_offset)
+{
+ const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
+ const bool show_vcol = true; //(update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0;
+ int tottri, totvert;
+ bool empty_mask = true;
+ TMFace *f = NULL;
+
+ /* Count visible triangles */
+ tottri = gpu_trimesh_face_visible_count(tm_faces);
+
+ if (buffers->smooth) {
+ /* Count visible vertices */
+ totvert = gpu_trimesh_vert_visible_count(bm_unique_verts, bm_other_verts);
+ }
+ else {
+ totvert = tottri * 3;
+ }
+
+ if (!tottri) {
+ if (BLI_gset_len(tm_faces) != 0) {
+ /* Node is just hidden. */
+ }
+ else {
+ buffers->clear_bmesh_on_flush = true;
+ }
+ buffers->tot_tri = 0;
+ return;
+ }
+
+ /* TODO, make mask layer optional for bmesh buffer */
+ const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
+
+ /* Fill vertex buffer */
+ if (!gpu_pbvh_vert_buf_data_set(buffers, totvert)) {
+ /* Memory map failed */
+ return;
+ }
+
+ int v_index = 0;
+
+ int cd_vcol_off = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL);
+
+ if (buffers->smooth) {
+ /* Fill the vertex and triangle buffer in one pass over faces. */
+ GPUIndexBufBuilder elb, elb_lines;
+ GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottri, totvert);
+ GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, totvert);
+
+ GHash *bm_vert_to_index = BLI_ghash_int_new_ex("bm_vert_to_index", totvert);
+
+ GSetIterator gs_iter;
+ GSET_ITER (gs_iter, tm_faces) {
+ f = BLI_gsetIterator_getKey(&gs_iter);
+
+ if (!TM_elem_flag_test(f, TM_ELEM_HIDDEN)) {
+ uint idx[3];
+ for (int i = 0; i < 3; i++) {
+ TMVert *v = TM_GET_TRI_VERT(f, i);
+
+ void **idx_p;
+ if (!BLI_ghash_ensure_p(bm_vert_to_index, v, &idx_p)) {
+ /* Add vertex to the vertex buffer each time a new one is encountered */
+ *idx_p = POINTER_FROM_UINT(v_index);
+
+ gpu_trimesh_vert_to_buffer_copy(v,
+ buffers->vert_buf,
+ v_index,
+ NULL,
+ NULL,
+ cd_vert_mask_offset,
+ cd_vert_node_offset,
+ show_mask,
+ show_vcol,
+ &empty_mask,
+ cd_vcol_off);
+
+ idx[i] = v_index;
+ v_index++;
+ }
+ else {
+ /* Vertex already in the vertex buffer, just get the index. */
+ idx[i] = POINTER_AS_UINT(*idx_p);
+ }
+ }
+
+ GPU_indexbuf_add_tri_verts(&elb, idx[0], idx[1], idx[2]);
+
+ GPU_indexbuf_add_line_verts(&elb_lines, idx[0], idx[1]);
+ GPU_indexbuf_add_line_verts(&elb_lines, idx[1], idx[2]);
+ GPU_indexbuf_add_line_verts(&elb_lines, idx[2], idx[0]);
+ }
+ }
+
+ BLI_ghash_free(bm_vert_to_index, NULL, NULL);
+
+ buffers->tot_tri = tottri;
+ if (buffers->index_buf == NULL) {
+ buffers->index_buf = GPU_indexbuf_build(&elb);
+ }
+ else {
+ GPU_indexbuf_build_in_place(&elb, buffers->index_buf);
+ }
+ buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines);
+ }
+ else {
+ GSetIterator gs_iter;
+
+ GPUIndexBufBuilder elb_lines;
+ GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, tottri * 3);
+
+ int cd_vcol_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL);
+
+ GSET_ITER (gs_iter, tm_faces) {
+ f = BLI_gsetIterator_getKey(&gs_iter);
+
+ BLI_assert(f->len == 3);
+
+ if (!TM_elem_flag_test(f, TM_ELEM_HIDDEN)) {
+ float fmask = 0.0f;
+ int i;
+
+ /* Average mask value */
+ for (i = 0; i < 3; i++) {
+ TMVert *v2 = TM_GET_TRI_VERT(f, i);
+
+ fmask += TM_ELEM_CD_GET_FLOAT(v2, cd_vert_mask_offset);
+ }
+ fmask /= 3.0f;
+
+ GPU_indexbuf_add_line_verts(&elb_lines, v_index + 0, v_index + 1);
+ GPU_indexbuf_add_line_verts(&elb_lines, v_index + 1, v_index + 2);
+ GPU_indexbuf_add_line_verts(&elb_lines, v_index + 2, v_index + 0);
+
+ for (i = 0; i < 3; i++) {
+ TMVert *v2 = TM_GET_TRI_VERT(f, i);
+
+ gpu_trimesh_vert_to_buffer_copy(v2,
+ buffers->vert_buf,
+ v_index++,
+ f->no,
+ &fmask,
+ cd_vert_mask_offset,
+ cd_vert_node_offset,
+ show_mask,
+ show_vcol,
+ &empty_mask,
+ cd_vcol_offset);
+ }
+ }
+ }
+
+ buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines);
+ buffers->tot_tri = tottri;
+ }
+
+ /* Get material index from the last face we iterated on. */
+ buffers->material_index = (f) ? f->mat_nr : 0;
+
+ buffers->show_overlay = !empty_mask;
+
+ gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS);
+}
/** \} */
/* -------------------------------------------------------------------- */
@@ -1061,6 +1371,19 @@ GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading)
return buffers;
}
+/* Threaded - do not call any functions that use OpenGL calls! */
+GPU_PBVH_Buffers *GPU_pbvh_trimesh_buffers_build(bool smooth_shading)
+{
+ GPU_PBVH_Buffers *buffers;
+
+ buffers = MEM_callocN(sizeof(GPU_PBVH_Buffers), "GPU_Buffers");
+ buffers->use_trimesh = true;
+ buffers->smooth = smooth_shading;
+ buffers->show_overlay = true;
+
+ return buffers;
+}
+
GPUBatch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast, bool wires)
{
if (wires) {
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index ae0bb20e529..761b3cd1d21 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -31,6 +31,8 @@
extern "C" {
#endif
+struct BLI_ThreadSafePool;
+
/** Descriptor and storage for a custom data layer. */
typedef struct CustomDataLayer {
/** Type of data in layer. */
@@ -82,7 +84,8 @@ typedef struct CustomData {
/** In editmode, total size of all data layers. */
int totsize;
/** (BMesh Only): Memory pool for allocation of blocks. */
- struct BLI_mempool *pool;
+ //struct BLI_mempool *pool;
+ struct BLI_ThreadSafePool *tpool;
/** External file storing customdata layers. */
CustomDataExternal *external;
} CustomData;
diff --git a/source/blender/makesdna/DNA_scene_defaults.h b/source/blender/makesdna/DNA_scene_defaults.h
index ae02ac5ee35..afdc595c8ec 100644
--- a/source/blender/makesdna/DNA_scene_defaults.h
+++ b/source/blender/makesdna/DNA_scene_defaults.h
@@ -141,6 +141,7 @@
.unit_line_thickness = 1.0f, \
\
.ffcodecdata = _DNA_DEFAULT_FFMpegCodecData, \
+ .hair_cyl_res = 6, \
}
#define _DNA_DEFAULT_AudioData \
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 0b63a085ee6..cd8a175da18 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -771,7 +771,7 @@ typedef struct RenderData {
short views_format;
/* Hair Display */
- short hair_type, hair_subdiv;
+ short hair_type, hair_subdiv, hair_cyl_res, _pad10[3];
/* Motion blur shutter */
struct CurveMapping mblur_shutter_curve;
@@ -786,6 +786,7 @@ typedef enum eQualityOption {
typedef enum eHairType {
SCE_HAIR_SHAPE_STRAND = 0,
SCE_HAIR_SHAPE_STRIP = 1,
+ SCE_HAIR_SHAPE_CYLINDER = 2,
} eHairType;
/* *************************************************************** */
diff --git a/source/blender/makesrna/intern/rna_context.c b/source/blender/makesrna/intern/rna_context.c
index e6dceb5af72..50324e78c8f 100644
--- a/source/blender/makesrna/intern/rna_context.c
+++ b/source/blender/makesrna/intern/rna_context.c
@@ -203,6 +203,8 @@ static int rna_Context_mode_get(PointerRNA *ptr)
return CTX_data_mode_enum(C);
}
+#include "BPY_extern.h"
+
static struct Depsgraph *rna_Context_evaluated_depsgraph_get(bContext *C)
{
struct Depsgraph *depsgraph;
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 91f1bbc03d7..bd3a1a217f3 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -2036,7 +2036,7 @@ bool rna_GPencil_object_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
int rna_Object_use_dynamic_topology_sculpting_get(PointerRNA *ptr)
{
SculptSession *ss = ((Object *)ptr->owner_id)->sculpt;
- return (ss && ss->bm);
+ return (ss && ss->tm);
}
#else
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 24cff501b59..3860af5dbf5 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -5781,6 +5781,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
static const EnumPropertyItem hair_shape_type_items[] = {
{SCE_HAIR_SHAPE_STRAND, "STRAND", 0, "Strand", ""},
{SCE_HAIR_SHAPE_STRIP, "STRIP", 0, "Strip", ""},
+ {SCE_HAIR_SHAPE_CYLINDER, "CYLINDER", 0, "Cylinder", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -6002,6 +6003,11 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Additional Subdiv", "Additional subdivision along the hair");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
+ prop = RNA_def_property(srna, "hair_cyl_res", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 64);
+ RNA_def_property_ui_text(prop, "Resolution", "Hair Cylinder Resolution");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
+
/* Performance */
prop = RNA_def_property(srna, "use_high_quality_normals", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "perf_flag", SCE_PERF_HQ_NORMALS);
diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c
index d6548834f2d..f6d9d0aea08 100644
--- a/source/blender/python/gpu/gpu_py_offscreen.c
+++ b/source/blender/python/gpu/gpu_py_offscreen.c
@@ -85,22 +85,17 @@ static PyObject *bpygpu_offscreen_new(PyTypeObject *UNUSED(self), PyObject *args
{
BPYGPU_IS_INIT_OR_ERROR_OBJ;
- GPUOffScreen *ofs = NULL;
- int width, height;
+ GPUOffScreen *ofs;
+ int width, height, high_bitdepth=0, samples = 0;
char err_out[256];
- static const char *_keywords[] = {"width", "height", NULL};
- static _PyArg_Parser _parser = {"ii|i:GPUOffScreen.__new__", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(args, kwds, &_parser, &width, &height)) {
+ static const char *_keywords[] = {"width", "height", "samples", "high_bitdepth", NULL};
+ static _PyArg_Parser _parser = {"ii|ii:GPUOffScreen.__new__", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(args, kwds, &_parser, &width, &height, &samples, &high_bitdepth)) {
return NULL;
}
- if (GPU_context_active_get()) {
- ofs = GPU_offscreen_create(width, height, true, false, err_out);
- }
- else {
- strncpy(err_out, "No active GPU context found", 256);
- }
+ ofs = GPU_offscreen_create(width, height, true, high_bitdepth, err_out);
if (ofs == NULL) {
PyErr_Format(PyExc_RuntimeError,