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:
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h10
-rw-r--r--source/blender/blenkernel/BKE_pbvh_pixels.hh7
-rw-r--r--source/blender/blenkernel/intern/pbvh.c30
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h2
-rw-r--r--source/blender/blenkernel/intern/pbvh_pixels.cc372
-rw-r--r--source/blender/draw/engines/basic/basic_engine.c12
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c11
-rw-r--r--source/blender/draw/intern/DRW_render.h4
-rw-r--r--source/blender/draw/intern/draw_manager_data.cc7
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c64
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h8
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_paint_color.c12
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_paint_image.cc71
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c2
14 files changed, 546 insertions, 66 deletions
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 42cd1536dcf..c3100dd2345 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -125,7 +125,8 @@ typedef enum {
PBVH_UpdateTopology = 1 << 13,
PBVH_UpdateColor = 1 << 14,
PBVH_RebuildPixels = 1 << 15,
- PBVH_TopologyUpdated = 1 << 16, /* Used internally by pbvh_bmesh.c */
+ PBVH_TexLeaf = 1 << 16,
+ PBVH_TopologyUpdated = 1 << 17, /* Used internally by pbvh_bmesh.c */
} PBVHNodeFlags;
@@ -299,7 +300,12 @@ void BKE_pbvh_search_callback(PBVH *pbvh,
void BKE_pbvh_search_gather(
PBVH *pbvh, BKE_pbvh_SearchCallback scb, void *search_data, PBVHNode ***array, int *tot);
-
+void BKE_pbvh_search_gather_ex(PBVH *pbvh,
+ BKE_pbvh_SearchCallback scb,
+ void *search_data,
+ PBVHNode ***r_array,
+ int *r_tot,
+ PBVHNodeFlags leaf_flag);
/* Ray-cast
* the hit callback is called for all leaf nodes intersecting the ray;
* it's up to the callback to find the primitive within the leaves that is
diff --git a/source/blender/blenkernel/BKE_pbvh_pixels.hh b/source/blender/blenkernel/BKE_pbvh_pixels.hh
index ad8eca2b36f..b8043a846b2 100644
--- a/source/blender/blenkernel/BKE_pbvh_pixels.hh
+++ b/source/blender/blenkernel/BKE_pbvh_pixels.hh
@@ -148,7 +148,7 @@ struct NodeData {
Vector<UDIMTilePixels> tiles;
Vector<UDIMTileUndo> undo_regions;
- Triangles triangles;
+ Triangles *triangles = nullptr;
NodeData()
{
@@ -169,6 +169,10 @@ struct NodeData {
{
undo_regions.clear();
for (UDIMTilePixels &tile : tiles) {
+ if (tile.pixel_rows.size() == 0) {
+ continue;
+ }
+
rcti region;
BLI_rcti_init_minmax(&region);
for (PackedPixelRow &pixel_row : tile.pixel_rows) {
@@ -201,7 +205,6 @@ struct NodeData {
void clear_data()
{
tiles.clear();
- triangles.clear();
}
static void free_func(void *instance)
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 65a906e6580..2b989885ebc 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -941,7 +941,9 @@ void BKE_pbvh_free(PBVH *pbvh)
if (node->bm_other_verts) {
BLI_gset_free(node->bm_other_verts, NULL);
}
+ }
+ if (node->flag & (PBVH_Leaf | PBVH_TexLeaf)) {
pbvh_pixels_free(node);
}
}
@@ -1013,7 +1015,7 @@ static void pbvh_stack_push(PBVHIter *iter, PBVHNode *node, bool revisiting)
iter->stacksize++;
}
-static PBVHNode *pbvh_iter_next(PBVHIter *iter)
+static PBVHNode *pbvh_iter_next(PBVHIter *iter, PBVHNodeFlags leaf_flag)
{
/* purpose here is to traverse tree, visiting child nodes before their
* parents, this order is necessary for e.g. computing bounding boxes */
@@ -1040,7 +1042,7 @@ static PBVHNode *pbvh_iter_next(PBVHIter *iter)
continue; /* don't traverse, outside of search zone */
}
- if (node->flag & PBVH_Leaf) {
+ if (node->flag & leaf_flag) {
/* immediately hit leaf node */
return node;
}
@@ -1085,8 +1087,12 @@ static PBVHNode *pbvh_iter_next_occluded(PBVHIter *iter)
return NULL;
}
-void BKE_pbvh_search_gather(
- PBVH *pbvh, BKE_pbvh_SearchCallback scb, void *search_data, PBVHNode ***r_array, int *r_tot)
+void BKE_pbvh_search_gather_ex(PBVH *pbvh,
+ BKE_pbvh_SearchCallback scb,
+ void *search_data,
+ PBVHNode ***r_array,
+ int *r_tot,
+ PBVHNodeFlags leaf_flag)
{
PBVHIter iter;
PBVHNode **array = NULL, *node;
@@ -1094,8 +1100,8 @@ void BKE_pbvh_search_gather(
pbvh_iter_begin(&iter, pbvh, scb, search_data);
- while ((node = pbvh_iter_next(&iter))) {
- if (node->flag & PBVH_Leaf) {
+ while ((node = pbvh_iter_next(&iter, leaf_flag))) {
+ if (node->flag & leaf_flag) {
if (UNLIKELY(tot == space)) {
/* resize array if needed */
space = (tot == 0) ? 32 : space * 2;
@@ -1118,6 +1124,12 @@ void BKE_pbvh_search_gather(
*r_tot = tot;
}
+void BKE_pbvh_search_gather(
+ PBVH *pbvh, BKE_pbvh_SearchCallback scb, void *search_data, PBVHNode ***r_array, int *r_tot)
+{
+ BKE_pbvh_search_gather_ex(pbvh, scb, search_data, r_array, r_tot, PBVH_Leaf);
+}
+
void BKE_pbvh_search_callback(PBVH *pbvh,
BKE_pbvh_SearchCallback scb,
void *search_data,
@@ -1129,7 +1141,7 @@ void BKE_pbvh_search_callback(PBVH *pbvh,
pbvh_iter_begin(&iter, pbvh, scb, search_data);
- while ((node = pbvh_iter_next(&iter))) {
+ while ((node = pbvh_iter_next(&iter, PBVH_Leaf))) {
if (node->flag & PBVH_Leaf) {
hcb(node, hit_data);
}
@@ -1867,7 +1879,7 @@ void BKE_pbvh_redraw_BB(PBVH *pbvh, float bb_min[3], float bb_max[3])
pbvh_iter_begin(&iter, pbvh, NULL, NULL);
- while ((node = pbvh_iter_next(&iter))) {
+ while ((node = pbvh_iter_next(&iter, PBVH_Leaf))) {
if (node->flag & PBVH_UpdateRedraw) {
BB_expand_with_bb(&bb, &node->vb);
}
@@ -1887,7 +1899,7 @@ void BKE_pbvh_get_grid_updates(PBVH *pbvh, bool clear, void ***r_gridfaces, int
pbvh_iter_begin(&iter, pbvh, NULL, NULL);
- while ((node = pbvh_iter_next(&iter))) {
+ while ((node = pbvh_iter_next(&iter, PBVH_Leaf))) {
if (node->flag & PBVH_UpdateNormals) {
for (uint i = 0; i < node->totprim; i++) {
void *face = pbvh->gridfaces[node->prim_indices[i]];
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index 368a9ffa1ea..34eb969adac 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -150,6 +150,8 @@ struct PBVH {
int totvert;
int leaf_limit;
+ int pixel_leaf_limit;
+ int depth_limit;
/* Mesh data */
struct Mesh *mesh;
diff --git a/source/blender/blenkernel/intern/pbvh_pixels.cc b/source/blender/blenkernel/intern/pbvh_pixels.cc
index df616d4e087..cbbd25d3f4b 100644
--- a/source/blender/blenkernel/intern/pbvh_pixels.cc
+++ b/source/blender/blenkernel/intern/pbvh_pixels.cc
@@ -14,20 +14,18 @@
#include "BLI_math.h"
#include "BLI_task.h"
+#include "PIL_time.h"
+#include "BKE_global.h"
#include "BKE_image_wrappers.hh"
#include "bmesh.h"
#include "pbvh_intern.h"
-namespace blender::bke::pbvh::pixels {
+#include <atomic>
-/**
- * During debugging this check could be enabled.
- * It will write to each image pixel that is covered by the PBVH.
- */
-constexpr bool USE_WATERTIGHT_CHECK = false;
+namespace blender::bke::pbvh::pixels {
/**
* Calculate the delta of two neighbor UV coordinates in the given image buffer.
@@ -55,6 +53,313 @@ static float2 calc_barycentric_delta_x(const ImBuf *image_buffer,
return calc_barycentric_delta(uvs, start_uv, end_uv);
}
+int count_node_pixels(PBVHNode &node)
+{
+ if (!node.pixels.node_data) {
+ return 0;
+ }
+
+ NodeData &data = BKE_pbvh_pixels_node_data_get(node);
+
+ int totpixel = 0;
+
+ for (UDIMTilePixels &tile : data.tiles) {
+ for (PackedPixelRow &row : tile.pixel_rows) {
+ totpixel += row.num_pixels;
+ }
+ }
+
+ return totpixel;
+}
+
+struct SplitQueueData {
+ ThreadQueue *new_nodes;
+ TaskPool *pool;
+
+ PBVH *pbvh;
+ Mesh *mesh;
+ Image *image;
+ ImageUser *image_user;
+};
+
+struct SplitNodePair {
+ SplitNodePair *parent;
+ PBVHNode node;
+ int children_offset = 0;
+ int depth = 0;
+ int source_index = -1;
+ bool is_old = false;
+ SplitQueueData *tdata;
+
+ SplitNodePair(SplitNodePair *node_parent = nullptr) : parent(node_parent)
+ {
+ memset(static_cast<void *>(&node), 0, sizeof(PBVHNode));
+ }
+};
+
+static void split_thread_job(TaskPool *__restrict pool, void *taskdata);
+
+static void split_pixel_node(PBVH *pbvh,
+ SplitNodePair *split,
+ Mesh *mesh,
+ Image *image,
+ ImageUser *image_user,
+ SplitQueueData *tdata)
+{
+ BB cb;
+ PBVHNode *node = &split->node;
+
+ cb = node->vb;
+
+ if (count_node_pixels(*node) <= pbvh->pixel_leaf_limit || split->depth >= pbvh->depth_limit) {
+ BKE_pbvh_pixels_node_data_get(split->node).rebuild_undo_regions();
+ return;
+ }
+
+ /* Find widest axis and its midpoint */
+ const int axis = BB_widest_axis(&cb);
+ const float mid = (cb.bmax[axis] + cb.bmin[axis]) * 0.5f;
+
+ node->flag = (PBVHNodeFlags)((int)node->flag & (int)~PBVH_TexLeaf);
+
+ SplitNodePair *split1 = MEM_new<SplitNodePair>("split_pixel_node split1", split);
+ SplitNodePair *split2 = MEM_new<SplitNodePair>("split_pixel_node split1", split);
+
+ split1->depth = split->depth + 1;
+ split2->depth = split->depth + 1;
+
+ PBVHNode *child1 = &split1->node;
+ PBVHNode *child2 = &split2->node;
+
+ child1->flag = PBVH_TexLeaf;
+ child2->flag = PBVH_TexLeaf;
+
+ child1->vb = cb;
+ child1->vb.bmax[axis] = mid;
+
+ child2->vb = cb;
+ child2->vb.bmin[axis] = mid;
+
+ NodeData &data = BKE_pbvh_pixels_node_data_get(split->node);
+
+ NodeData *data1 = MEM_new<NodeData>(__func__);
+ NodeData *data2 = MEM_new<NodeData>(__func__);
+ child1->pixels.node_data = static_cast<void *>(data1);
+ child2->pixels.node_data = static_cast<void *>(data2);
+
+ data1->triangles = data.triangles;
+ data2->triangles = data.triangles;
+
+ data1->tiles.resize(data.tiles.size());
+ data2->tiles.resize(data.tiles.size());
+
+ for (int i : IndexRange(data.tiles.size())) {
+ UDIMTilePixels &tile = data.tiles[i];
+ UDIMTilePixels &tile1 = data1->tiles[i];
+ UDIMTilePixels &tile2 = data2->tiles[i];
+
+ tile1.tile_number = tile2.tile_number = tile.tile_number;
+ tile1.flags.dirty = tile2.flags.dirty = 0;
+ }
+
+ ImageUser image_user2 = *image_user;
+
+ for (int i : IndexRange(data.tiles.size())) {
+ const UDIMTilePixels &tile = data.tiles[i];
+
+ image_user2.tile = tile.tile_number;
+
+ ImBuf *image_buffer = BKE_image_acquire_ibuf(image, &image_user2, nullptr);
+ if (image_buffer == nullptr) {
+ continue;
+ }
+
+ const MVert *mvert = BKE_pbvh_get_verts(pbvh);
+
+ for (const PackedPixelRow &row : tile.pixel_rows) {
+ UDIMTilePixels *tile1 = &data1->tiles[i];
+ UDIMTilePixels *tile2 = &data2->tiles[i];
+
+ TrianglePaintInput &tri = data.triangles->paint_input[row.triangle_index];
+
+ float verts[3][3];
+
+ copy_v3_v3(verts[0], mvert[tri.vert_indices[0]].co);
+ copy_v3_v3(verts[1], mvert[tri.vert_indices[1]].co);
+ copy_v3_v3(verts[2], mvert[tri.vert_indices[2]].co);
+
+ float2 delta = tri.delta_barycentric_coord_u;
+ float2 uv1 = row.start_barycentric_coord;
+ float2 uv2 = row.start_barycentric_coord + delta * (float)row.num_pixels;
+
+ float co1[3];
+ float co2[3];
+
+ interp_barycentric_tri_v3(verts, uv1[0], uv1[1], co1);
+ interp_barycentric_tri_v3(verts, uv2[0], uv2[1], co2);
+
+ /* Are we spanning the midpoint? */
+ if ((co1[axis] <= mid) != (co2[axis] <= mid)) {
+ PackedPixelRow row1 = row;
+ float t;
+
+ if (mid < co1[axis]) {
+ t = 1.0f - (mid - co2[axis]) / (co1[axis] - co2[axis]);
+
+ SWAP(UDIMTilePixels *, tile1, tile2);
+ }
+ else {
+ t = (mid - co1[axis]) / (co2[axis] - co1[axis]);
+ }
+
+ int num_pixels = (int)floorf((float)row.num_pixels * t);
+
+ if (num_pixels) {
+ row1.num_pixels = num_pixels;
+ tile1->pixel_rows.append(row1);
+ }
+
+ if (num_pixels != row.num_pixels) {
+ PackedPixelRow row2 = row;
+
+ row2.num_pixels = row.num_pixels - num_pixels;
+
+ row2.start_barycentric_coord = row.start_barycentric_coord +
+ tri.delta_barycentric_coord_u * (float)num_pixels;
+ row2.start_image_coordinate = row.start_image_coordinate;
+ row2.start_image_coordinate[0] += num_pixels;
+
+ tile2->pixel_rows.append(row2);
+ }
+ }
+ else if (co1[axis] <= mid && co2[axis] <= mid) {
+ tile1->pixel_rows.append(row);
+ }
+ else {
+ tile2->pixel_rows.append(row);
+ }
+ }
+
+ BKE_image_release_ibuf(image, image_buffer, nullptr);
+ }
+
+ if (node->flag & PBVH_Leaf) {
+ data.clear_data();
+ }
+ else {
+ pbvh_pixels_free(node);
+ }
+
+ data.undo_regions.clear();
+
+ BLI_thread_queue_push(tdata->new_nodes, static_cast<void *>(split1));
+ BLI_thread_queue_push(tdata->new_nodes, static_cast<void *>(split2));
+
+ BLI_task_pool_push(tdata->pool, split_thread_job, static_cast<void *>(split1), false, nullptr);
+ BLI_task_pool_push(tdata->pool, split_thread_job, static_cast<void *>(split2), false, nullptr);
+}
+
+static void split_flush_final_nodes(SplitQueueData *tdata)
+{
+ PBVH *pbvh = tdata->pbvh;
+ Vector<SplitNodePair *> splits;
+
+ while (!BLI_thread_queue_is_empty(tdata->new_nodes)) {
+ SplitNodePair *newsplit = static_cast<SplitNodePair *>(BLI_thread_queue_pop(tdata->new_nodes));
+
+ splits.append(newsplit);
+
+ if (newsplit->is_old) {
+ continue;
+ }
+
+ if (!newsplit->parent->children_offset) {
+ newsplit->parent->children_offset = pbvh->totnode;
+
+ pbvh_grow_nodes(pbvh, pbvh->totnode + 2);
+ newsplit->source_index = newsplit->parent->children_offset;
+ }
+ else {
+ newsplit->source_index = newsplit->parent->children_offset + 1;
+ }
+ }
+
+ for (SplitNodePair *split : splits) {
+ BLI_assert(split->source_index != -1);
+
+ split->node.children_offset = split->children_offset;
+ pbvh->nodes[split->source_index] = split->node;
+ }
+
+ for (SplitNodePair *split : splits) {
+ MEM_delete<SplitNodePair>(split);
+ }
+}
+
+static void split_thread_job(TaskPool *__restrict pool, void *taskdata)
+{
+
+ SplitQueueData *tdata = static_cast<SplitQueueData *>(BLI_task_pool_user_data(pool));
+ SplitNodePair *split = static_cast<SplitNodePair *>(taskdata);
+
+ split_pixel_node(tdata->pbvh, split, tdata->mesh, tdata->image, tdata->image_user, tdata);
+}
+
+static void split_pixel_nodes(PBVH *pbvh, Mesh *mesh, Image *image, ImageUser *image_user)
+{
+ if (G.debug_value == 891) {
+ return;
+ }
+
+ if (!pbvh->depth_limit) {
+ pbvh->depth_limit = 40; /* TODO: move into a constant */
+ }
+
+ if (!pbvh->pixel_leaf_limit) {
+ pbvh->pixel_leaf_limit = 256 * 256; /* TODO: move into a constant */
+ }
+
+ SplitQueueData tdata;
+ TaskPool *pool = BLI_task_pool_create_suspended(&tdata, TASK_PRIORITY_HIGH);
+
+ tdata.pool = pool;
+ tdata.pbvh = pbvh;
+ tdata.mesh = mesh;
+ tdata.image = image;
+ tdata.image_user = image_user;
+
+ tdata.new_nodes = BLI_thread_queue_init();
+
+ /* Set up initial jobs before initializing threads. */
+ for (int i : IndexRange(pbvh->totnode)) {
+ if (pbvh->nodes[i].flag & PBVH_TexLeaf) {
+ SplitNodePair *split = MEM_new<SplitNodePair>("split_pixel_nodes split");
+
+ split->source_index = i;
+ split->is_old = true;
+ split->node = pbvh->nodes[i];
+ split->tdata = &tdata;
+
+ BLI_task_pool_push(pool, split_thread_job, static_cast<void *>(split), false, nullptr);
+
+ BLI_thread_queue_push(tdata.new_nodes, static_cast<void *>(split));
+ }
+ }
+
+ BLI_task_pool_work_and_wait(pool);
+ BLI_task_pool_free(pool);
+
+ split_flush_final_nodes(&tdata);
+
+ BLI_thread_queue_free(tdata.new_nodes);
+}
+
+/**
+ * During debugging this check could be enabled.
+ * It will write to each image pixel that is covered by the PBVH.
+ */
+constexpr bool USE_WATERTIGHT_CHECK = false;
+
static void extract_barycentric_pixels(UDIMTilePixels &tile_data,
const ImBuf *image_buffer,
const int triangle_index,
@@ -97,9 +402,15 @@ static void extract_barycentric_pixels(UDIMTilePixels &tile_data,
static void init_triangles(PBVH *pbvh, PBVHNode *node, NodeData *node_data, const MLoop *mloop)
{
+ if (node_data->triangles) {
+ MEM_delete<Triangles>(node_data->triangles);
+ }
+
+ node_data->triangles = MEM_new<Triangles>("triangles");
+
for (int i = 0; i < node->totprim; i++) {
const MLoopTri *lt = &pbvh->looptri[node->prim_indices[i]];
- node_data->triangles.append(
+ node_data->triangles->append(
int3(mloop[lt->tri[0]].v, mloop[lt->tri[1]].v, mloop[lt->tri[2]].v));
}
}
@@ -133,7 +444,7 @@ static void do_encode_pixels(void *__restrict userdata,
float2 tile_offset = float2(image_tile.get_tile_offset());
UDIMTilePixels tile_data;
- Triangles &triangles = node_data->triangles;
+ Triangles &triangles = *node_data->triangles;
for (int triangle_index = 0; triangle_index < triangles.size(); triangle_index++) {
const MLoopTri *lt = &pbvh->looptri[node->prim_indices[triangle_index]];
float2 uvs[3] = {
@@ -173,6 +484,9 @@ static bool should_pixels_be_updated(PBVHNode *node)
if ((node->flag & PBVH_Leaf) == 0) {
return false;
}
+ if (node->children_offset != 0) {
+ return false;
+ }
if ((node->flag & PBVH_RebuildPixels) != 0) {
return true;
}
@@ -228,6 +542,11 @@ static bool find_nodes_to_update(PBVH *pbvh, Vector<PBVHNode *> &r_nodes_to_upda
else {
NodeData *node_data = static_cast<NodeData *>(node->pixels.node_data);
node_data->clear_data();
+
+ if (node_data->triangles && (node->flag & PBVH_Leaf)) {
+ MEM_delete<Triangles>(node_data->triangles);
+ node_data->triangles = nullptr;
+ }
}
}
@@ -276,18 +595,18 @@ static void apply_watertight_check(PBVH *pbvh, Image *image, ImageUser *image_us
BKE_image_partial_update_mark_full_update(image);
}
-static void update_pixels(PBVH *pbvh, Mesh *mesh, Image *image, ImageUser *image_user)
+static bool update_pixels(PBVH *pbvh, Mesh *mesh, Image *image, ImageUser *image_user)
{
Vector<PBVHNode *> nodes_to_update;
if (!find_nodes_to_update(pbvh, nodes_to_update)) {
- return;
+ return false;
}
const MLoopUV *ldata_uv = static_cast<const MLoopUV *>(
CustomData_get_layer(&mesh->ldata, CD_MLOOPUV));
if (ldata_uv == nullptr) {
- return;
+ return false;
}
for (PBVHNode *node : nodes_to_update) {
@@ -321,6 +640,15 @@ static void update_pixels(PBVH *pbvh, Mesh *mesh, Image *image, ImageUser *image
node->flag = static_cast<PBVHNodeFlags>(node->flag & ~PBVH_RebuildPixels);
}
+ /* Add PBVH_TexLeaf flag */
+ for (int i : IndexRange(pbvh->totnode)) {
+ PBVHNode &node = pbvh->nodes[i];
+
+ if (node.flag & PBVH_Leaf) {
+ node.flag = (PBVHNodeFlags)((int)node.flag | (int)PBVH_TexLeaf);
+ }
+ }
+
//#define DO_PRINT_STATISTICS
#ifdef DO_PRINT_STATISTICS
/* Print some statistics about compression ratio. */
@@ -347,6 +675,8 @@ static void update_pixels(PBVH *pbvh, Mesh *mesh, Image *image, ImageUser *image
float(compressed_data_len) / num_pixels);
}
#endif
+
+ return true;
}
NodeData &BKE_pbvh_pixels_node_data_get(PBVHNode &node)
@@ -376,7 +706,6 @@ void BKE_pbvh_pixels_mark_image_dirty(PBVHNode &node, Image &image, ImageUser &i
node_data->flags.dirty = false;
}
}
-
} // namespace blender::bke::pbvh::pixels
extern "C" {
@@ -384,12 +713,29 @@ using namespace blender::bke::pbvh::pixels;
void BKE_pbvh_build_pixels(PBVH *pbvh, Mesh *mesh, Image *image, ImageUser *image_user)
{
- update_pixels(pbvh, mesh, image, image_user);
+ if (update_pixels(pbvh, mesh, image, image_user)) {
+ double time_ms = PIL_check_seconds_timer();
+
+ split_pixel_nodes(pbvh, mesh, image, image_user);
+
+ time_ms = PIL_check_seconds_timer() - time_ms;
+
+ printf("Nodes split time: %.2fms\n", time_ms * 1000.0);
+ }
}
void pbvh_pixels_free(PBVHNode *node)
{
NodeData *node_data = static_cast<NodeData *>(node->pixels.node_data);
+
+ if (!node_data) {
+ return;
+ }
+
+ if (node_data->triangles && (node->flag & PBVH_Leaf)) {
+ MEM_delete<Triangles>(node_data->triangles);
+ }
+
MEM_delete(node_data);
node->pixels.node_data = nullptr;
}
diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c
index eee6a5a7cb5..c7da286c064 100644
--- a/source/blender/draw/engines/basic/basic_engine.c
+++ b/source/blender/draw/engines/basic/basic_engine.c
@@ -10,9 +10,11 @@
#include "DRW_render.h"
+#include "BKE_global.h"
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
+#include "BKE_pbvh.h"
#include "BLI_alloca.h"
@@ -221,6 +223,16 @@ static void basic_cache_populate(void *vedata, Object *ob)
DRW_shgroup_call(shgrp, geom, ob);
}
}
+
+ if (G.debug_value == 889 && ob->sculpt && ob->sculpt->pbvh) {
+ int debug_node_nr = 0;
+ DRW_debug_modelmat(ob->obmat);
+ BKE_pbvh_draw_debug_cb(
+ ob->sculpt->pbvh,
+ (void (*)(void *d, const float min[3], const float max[3], PBVHNodeFlags f))
+ DRW_sculpt_debug_cb,
+ &debug_node_nr);
+ }
}
}
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index f79e4e1d568..c454a58ffe9 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -15,6 +15,7 @@
#include "BLI_rand.h"
#include "BLI_string_utils.h"
+#include "BKE_global.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
@@ -882,6 +883,16 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
*cast_shadow = *cast_shadow || (matcache[i].shadow_grp != NULL);
}
}
+
+ if (G.debug_value == 889 && ob->sculpt && ob->sculpt->pbvh) {
+ int debug_node_nr = 0;
+ DRW_debug_modelmat(ob->obmat);
+ BKE_pbvh_draw_debug_cb(
+ ob->sculpt->pbvh,
+ (void (*)(void *d, const float min[3], const float max[3], PBVHNodeFlags f))
+ DRW_sculpt_debug_cb,
+ &debug_node_nr);
+ }
}
/* Motion Blur Vectors. */
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index b9444c58191..7920d9fc71b 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -17,6 +17,7 @@
#include "BKE_context.h"
#include "BKE_layer.h"
#include "BKE_material.h"
+#include "BKE_pbvh.h"
#include "BKE_scene.h"
#include "BLT_translation.h"
@@ -949,6 +950,9 @@ void DRW_mesh_batch_cache_get_attributes(struct Object *object,
struct DRW_Attributes **r_attrs,
struct DRW_MeshCDMask **r_cd_needed);
+void DRW_sculpt_debug_cb(
+ PBVHNode *node, void *user_data, const float bmin[3], const float bmax[3], PBVHNodeFlags flag);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/draw/intern/draw_manager_data.cc b/source/blender/draw/intern/draw_manager_data.cc
index 9768f1ce9e7..0312eecc7b7 100644
--- a/source/blender/draw/intern/draw_manager_data.cc
+++ b/source/blender/draw/intern/draw_manager_data.cc
@@ -1250,7 +1250,7 @@ static void sculpt_draw_cb(DRWSculptCallbackData *scd,
}
}
-static void sculpt_debug_cb(
+void DRW_sculpt_debug_cb(
PBVHNode *node, void *user_data, const float bmin[3], const float bmax[3], PBVHNodeFlags flag)
{
int *debug_node_nr = (int *)user_data;
@@ -1265,7 +1265,8 @@ static void sculpt_debug_cb(
DRW_debug_bbox(&bb, (float[4]){0.5f, 0.5f, 0.5f, 0.6f});
}
#else /* Color coded leaf bounds. */
- if (flag & PBVH_Leaf) {
+ if (flag & (PBVH_Leaf | PBVH_TexLeaf)) {
+ DRW_debug_bbox(&bb, SCULPT_DEBUG_COLOR((*debug_node_nr)++));
int color = (*debug_node_nr)++;
color += BKE_pbvh_debug_draw_gen_get(node);
@@ -1365,7 +1366,7 @@ static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd)
BKE_pbvh_draw_debug_cb(
pbvh,
(void (*)(PBVHNode * n, void *d, const float min[3], const float max[3], PBVHNodeFlags f))
- sculpt_debug_cb,
+ DRW_sculpt_debug_cb,
&debug_node_nr);
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index c46fd019725..37a630b8065 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -2665,12 +2665,13 @@ static PBVHNode **sculpt_pbvh_gather_cursor_update(Object *ob,
return nodes;
}
-static PBVHNode **sculpt_pbvh_gather_generic(Object *ob,
- Sculpt *sd,
- const Brush *brush,
- bool use_original,
- float radius_scale,
- int *r_totnode)
+static PBVHNode **sculpt_pbvh_gather_generic_intern(Object *ob,
+ Sculpt *sd,
+ const Brush *brush,
+ bool use_original,
+ float radius_scale,
+ int *r_totnode,
+ PBVHNodeFlags flag)
{
SculptSession *ss = ob->sculpt;
PBVHNode **nodes = NULL;
@@ -2686,7 +2687,8 @@ static PBVHNode **sculpt_pbvh_gather_generic(Object *ob,
.ignore_fully_ineffective = brush->sculpt_tool != SCULPT_TOOL_MASK,
.center = NULL,
};
- BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, r_totnode);
+
+ BKE_pbvh_search_gather_ex(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, r_totnode, flag);
}
else {
struct DistRayAABB_Precalc dist_ray_to_aabb_precalc;
@@ -2701,11 +2703,33 @@ static PBVHNode **sculpt_pbvh_gather_generic(Object *ob,
.dist_ray_to_aabb_precalc = &dist_ray_to_aabb_precalc,
.ignore_fully_ineffective = brush->sculpt_tool != SCULPT_TOOL_MASK,
};
- BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_circle_cb, &data, &nodes, r_totnode);
+ BKE_pbvh_search_gather_ex(ss->pbvh, SCULPT_search_circle_cb, &data, &nodes, r_totnode, flag);
}
return nodes;
}
+static PBVHNode **sculpt_pbvh_gather_generic(Object *ob,
+ Sculpt *sd,
+ const Brush *brush,
+ bool use_original,
+ float radius_scale,
+ int *r_totnode)
+{
+ return sculpt_pbvh_gather_generic_intern(
+ ob, sd, brush, use_original, radius_scale, r_totnode, PBVH_Leaf);
+}
+
+static PBVHNode **sculpt_pbvh_gather_texpaint(Object *ob,
+ Sculpt *sd,
+ const Brush *brush,
+ bool use_original,
+ float radius_scale,
+ int *r_totnode)
+{
+ return sculpt_pbvh_gather_generic_intern(
+ ob, sd, brush, use_original, radius_scale, r_totnode, PBVH_TexLeaf);
+}
+
/* Calculate primary direction of movement for many brushes. */
static void calc_sculpt_normal(
Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3])
@@ -3328,8 +3352,8 @@ static void do_brush_action(Sculpt *sd,
PaintModeSettings *paint_mode_settings)
{
SculptSession *ss = ob->sculpt;
- int totnode;
- PBVHNode **nodes;
+ int totnode, texnodes_num = 0;
+ PBVHNode **nodes, **texnodes = NULL;
/* Check for unsupported features. */
PBVHType type = BKE_pbvh_type(ss->pbvh);
@@ -3342,6 +3366,19 @@ static void do_brush_action(Sculpt *sd,
BKE_pbvh_ensure_node_loops(ss->pbvh);
}
+ const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true :
+ ss->cache->original;
+
+ if (sculpt_needs_pbvh_pixels(paint_mode_settings, brush, ob)) {
+ sculpt_pbvh_update_pixels(paint_mode_settings, ss, ob);
+
+ texnodes = sculpt_pbvh_gather_texpaint(ob, sd, brush, use_original, 1.0f, &texnodes_num);
+
+ if (!texnodes_num) {
+ return;
+ }
+ }
+
/* Build a list of all nodes that are potentially within the brush's area of influence */
if (SCULPT_tool_needs_all_pbvh_nodes(brush)) {
@@ -3352,8 +3389,6 @@ static void do_brush_action(Sculpt *sd,
nodes = SCULPT_cloth_brush_affected_nodes_gather(ss, brush, &totnode);
}
else {
- const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true :
- ss->cache->original;
float radius_scale = 1.0f;
/* Corners of square brushes can go outside the brush radius. */
@@ -3368,6 +3403,7 @@ static void do_brush_action(Sculpt *sd,
}
nodes = sculpt_pbvh_gather_generic(ob, sd, brush, use_original, radius_scale, &totnode);
}
+
const bool use_pixels = sculpt_needs_pbvh_pixels(paint_mode_settings, brush, ob);
if (use_pixels) {
sculpt_pbvh_update_pixels(paint_mode_settings, ss, ob);
@@ -3420,6 +3456,7 @@ static void do_brush_action(Sculpt *sd,
/* Only act if some verts are inside the brush area. */
if (totnode == 0) {
+ MEM_SAFE_FREE(texnodes);
return;
}
float location[3];
@@ -3567,7 +3604,7 @@ static void do_brush_action(Sculpt *sd,
SCULPT_do_displacement_smear_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_PAINT:
- SCULPT_do_paint_brush(paint_mode_settings, sd, ob, nodes, totnode);
+ SCULPT_do_paint_brush(paint_mode_settings, sd, ob, nodes, totnode, texnodes, texnodes_num);
break;
case SCULPT_TOOL_SMEAR:
SCULPT_do_smear_brush(sd, ob, nodes, totnode);
@@ -3611,6 +3648,7 @@ static void do_brush_action(Sculpt *sd,
}
MEM_SAFE_FREE(nodes);
+ MEM_SAFE_FREE(texnodes);
/* Update average stroke position. */
copy_v3_v3(location, ss->cache->true_location);
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index bf47b64d176..59b0f7f5925 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -1743,7 +1743,9 @@ void SCULPT_do_paint_brush(struct PaintModeSettings *paint_mode_settings,
Sculpt *sd,
Object *ob,
PBVHNode **nodes,
- int totnode) ATTR_NONNULL();
+ int totnode,
+ PBVHNode **texnodes,
+ int texnodes_num) ATTR_NONNULL();
/**
* \brief Get the image canvas for painting on the given object.
@@ -1760,7 +1762,9 @@ void SCULPT_do_paint_brush_image(struct PaintModeSettings *paint_mode_settings,
Sculpt *sd,
Object *ob,
PBVHNode **nodes,
- int totnode) ATTR_NONNULL();
+ int totnode,
+ PBVHNode **texnodes,
+ int texnode_num) ATTR_NONNULL();
bool SCULPT_use_image_paint_brush(struct PaintModeSettings *settings, Object *ob) ATTR_NONNULL();
/* Smear Brush. */
diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_color.c b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
index ee716d1107a..2826a7c4df3 100644
--- a/source/blender/editors/sculpt_paint/sculpt_paint_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
@@ -249,11 +249,17 @@ static void sample_wet_paint_reduce(const void *__restrict UNUSED(userdata),
add_v4_v4(join->color, swptd->color);
}
-void SCULPT_do_paint_brush(
- PaintModeSettings *paint_mode_settings, Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+void SCULPT_do_paint_brush(PaintModeSettings *paint_mode_settings,
+ Sculpt *sd,
+ Object *ob,
+ PBVHNode **nodes,
+ int totnode,
+ PBVHNode **texnodes,
+ int texnodes_num)
{
if (SCULPT_use_image_paint_brush(paint_mode_settings, ob)) {
- SCULPT_do_paint_brush_image(paint_mode_settings, sd, ob, nodes, totnode);
+ SCULPT_do_paint_brush_image(
+ paint_mode_settings, sd, ob, nodes, totnode, texnodes, texnodes_num);
return;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_image.cc b/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
index d3b3100458d..cb4bb1cde5c 100644
--- a/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
+++ b/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
@@ -1,6 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2022 Blender Foundation. All rights reserved. */
+/* Paint a color made from hash of node pointer. */
+//#define DEBUG_PIXEL_NODES
+
#include "DNA_image_types.h"
#include "DNA_object_types.h"
@@ -9,6 +12,9 @@
#include "BLI_math.h"
#include "BLI_math_color_blend.h"
#include "BLI_task.h"
+#ifdef DEBUG_PIXEL_NODES
+# include "BLI_rand.h"
+#endif
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
@@ -181,6 +187,15 @@ template<typename ImageBuffer> class PaintingKernel {
automask_data);
float4 paint_color = brush_color * falloff_strength * brush_strength;
float4 buffer_color;
+
+#ifdef DEBUG_PIXEL_NODES
+ if ((pixel_row.start_image_coordinate.y >> 3) & 1) {
+ paint_color[0] *= 0.5f;
+ paint_color[1] *= 0.5f;
+ paint_color[2] *= 0.5f;
+ }
+#endif
+
blend_color_mix_float(buffer_color, color, paint_color);
buffer_color *= brush->alpha;
IMB_blend_color_float(color, color, buffer_color, static_cast<IMB_BlendMode>(brush->blend));
@@ -193,20 +208,18 @@ template<typename ImageBuffer> class PaintingKernel {
return pixels_painted;
}
- void init_brush_color(ImBuf *image_buffer)
+ void init_brush_color(ImBuf *image_buffer, float in_brush_color[3])
{
const char *to_colorspace = image_accessor.get_colorspace_name(image_buffer);
if (last_used_color_space == to_colorspace) {
return;
}
- copy_v3_v3(brush_color,
- ss->cache->invert ? BKE_brush_secondary_color_get(ss->scene, brush) :
- BKE_brush_color_get(ss->scene, brush));
+
/* NOTE: Brush colors are stored in sRGB. We use math color to follow other areas that
* use brush colors. From there on we use IMB_colormanagement to convert the brush color to the
* colorspace of the texture. This isn't ideal, but would need more refactoring to make sure
* that brush colors are stored in scene linear by default. */
- srgb_to_linearrgb_v3_v3(brush_color, brush_color);
+ srgb_to_linearrgb_v3_v3(brush_color, in_brush_color);
brush_color[3] = 1.0f;
const char *from_colorspace = IMB_colormanagement_role_colorspace_name_get(
@@ -314,11 +327,27 @@ static void do_paint_pixels(void *__restrict userdata,
const int thread_id = BLI_task_parallel_thread_id(tls);
MVert *mvert = SCULPT_mesh_deformed_mverts_get(ss);
- std::vector<bool> brush_test = init_triangle_brush_test(ss, node_data.triangles, mvert);
+ std::vector<bool> brush_test = init_triangle_brush_test(ss, *node_data.triangles, mvert);
PaintingKernel<ImageBufferFloat4> kernel_float4(ss, brush, thread_id, mvert);
PaintingKernel<ImageBufferByte4> kernel_byte4(ss, brush, thread_id, mvert);
+ float brush_color[4];
+
+#ifdef DEBUG_PIXEL_NODES
+ RNG *rng = BLI_rng_new(POINTER_AS_UINT(node));
+
+ brush_color[0] = BLI_rng_get_float(rng);
+ brush_color[1] = BLI_rng_get_float(rng);
+ brush_color[2] = BLI_rng_get_float(rng);
+#else
+ copy_v3_v3(brush_color,
+ ss->cache->invert ? BKE_brush_secondary_color_get(ss->scene, brush) :
+ BKE_brush_color_get(ss->scene, brush));
+#endif
+
+ brush_color[3] = 1.0f;
+
AutomaskingNodeData automask_data;
SCULPT_automasking_node_begin(ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]);
@@ -336,10 +365,10 @@ static void do_paint_pixels(void *__restrict userdata,
}
if (image_buffer->rect_float != nullptr) {
- kernel_float4.init_brush_color(image_buffer);
+ kernel_float4.init_brush_color(image_buffer, brush_color);
}
else {
- kernel_byte4.init_brush_color(image_buffer);
+ kernel_byte4.init_brush_color(image_buffer, brush_color);
}
for (const PackedPixelRow &pixel_row : tile_data.pixel_rows) {
@@ -349,11 +378,11 @@ static void do_paint_pixels(void *__restrict userdata,
bool pixels_painted = false;
if (image_buffer->rect_float != nullptr) {
pixels_painted = kernel_float4.paint(
- node_data.triangles, pixel_row, image_buffer, &automask_data);
+ *node_data.triangles, pixel_row, image_buffer, &automask_data);
}
else {
pixels_painted = kernel_byte4.paint(
- node_data.triangles, pixel_row, image_buffer, &automask_data);
+ *node_data.triangles, pixel_row, image_buffer, &automask_data);
}
if (pixels_painted) {
@@ -497,27 +526,33 @@ bool SCULPT_use_image_paint_brush(PaintModeSettings *settings, Object *ob)
return BKE_paint_canvas_image_get(settings, ob, &image, &image_user);
}
-void SCULPT_do_paint_brush_image(
- PaintModeSettings *paint_mode_settings, Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+void SCULPT_do_paint_brush_image(PaintModeSettings *paint_mode_settings,
+ Sculpt *sd,
+ Object *ob,
+ PBVHNode **nodes,
+ int totnode,
+ PBVHNode **texnodes,
+ int texnodes_num)
{
Brush *brush = BKE_paint_brush(&sd->paint);
TexturePaintingUserData data = {nullptr};
data.ob = ob;
data.brush = brush;
- data.nodes = nodes;
+ data.nodes = texnodes;
if (!ImageData::init_active_image(ob, &data.image_data, paint_mode_settings)) {
return;
}
TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_push_undo_tile, &settings);
- BLI_task_parallel_range(0, totnode, &data, do_paint_pixels, &settings);
+ BKE_pbvh_parallel_range_settings(&settings, true, texnodes_num);
+ BLI_task_parallel_range(0, texnodes_num, &data, do_push_undo_tile, &settings);
+ BLI_task_parallel_range(0, texnodes_num, &data, do_paint_pixels, &settings);
TaskParallelSettings settings_flush;
- BKE_pbvh_parallel_range_settings(&settings_flush, false, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_mark_dirty_regions, &settings_flush);
+
+ BKE_pbvh_parallel_range_settings(&settings_flush, false, texnodes_num);
+ BLI_task_parallel_range(0, texnodes_num, &data, do_mark_dirty_regions, &settings_flush);
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 13e3dd64521..518e7477b4d 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -2068,7 +2068,7 @@ static UndoSculpt *sculpt_undo_get_nodes(void)
{
UndoStack *ustack = ED_undo_stack_get();
UndoStep *us = BKE_undosys_stack_init_or_active_with_type(ustack, BKE_UNDOSYS_TYPE_SCULPT);
- return sculpt_undosys_step_get_nodes(us);
+ return us ? sculpt_undosys_step_get_nodes(us) : NULL;
}
/** \} */