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:
authorJeroen Bakker <jeroen@blender.org>2022-03-07 17:23:30 +0300
committerJeroen Bakker <jeroen@blender.org>2022-03-07 17:23:30 +0300
commit4cbeae12fd7d2da0144674548c589b8bb3dc736e (patch)
tree02a40ac36ede1713a09b1e22dc6242d3309c84e9
parentb522eb820707a601c747b47eaf0f4d711611ba34 (diff)
Texture painting second experiment.
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h17
-rw-r--r--source/blender/blenkernel/intern/pbvh.c30
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h1
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c11
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_texture_paint_a.cc5
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_texture_paint_b.cc315
-rw-r--r--source/blender/imbuf/IMB_rasterizer.hh5
-rw-r--r--source/blender/imbuf/intern/rasterizer_target.hh11
10 files changed, 314 insertions, 85 deletions
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 6c8880fea7c..9078db149f2 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -46,6 +46,12 @@ typedef struct {
float (*color)[4];
} PBVHColorBufferNode;
+typedef void (*PBVHNodeTexturePaintDataFreeFunc)(void *ptr);
+typedef struct PBVHTexturePaintingNode {
+ void *data;
+ PBVHNodeTexturePaintDataFreeFunc free_func;
+} PBVHTexturePaintingNode;
+
typedef enum {
PBVH_Leaf = 1 << 0,
@@ -416,7 +422,7 @@ BLI_INLINE struct BMVert *PBVH_cast_bmvert(void *src)
}
BLI_INLINE float *PBVH_cast_float_ptr(void *src)
{
- return static_cast<float*>(src);
+ return static_cast<float *>(src);
}
#else
BLI_INLINE struct BMVert *PBVH_cast_bmvert(void *src)
@@ -501,7 +507,8 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
vi.co = vi.bm_vert->co; \
vi.fno = vi.bm_vert->no; \
vi.index = BM_elem_index_get(vi.bm_vert); \
- vi.mask = PBVH_cast_float_ptr(BM_ELEM_CD_GET_VOID_P(vi.bm_vert, vi.cd_vert_mask_offset)); \
+ vi.mask = PBVH_cast_float_ptr( \
+ BM_ELEM_CD_GET_VOID_P(vi.bm_vert, vi.cd_vert_mask_offset)); \
}
#define BKE_pbvh_vertex_iter_end \
@@ -547,6 +554,12 @@ const float (*BKE_pbvh_get_vert_normals(const PBVH *pbvh))[3];
PBVHColorBufferNode *BKE_pbvh_node_color_buffer_get(PBVHNode *node);
void BKE_pbvh_node_color_buffer_free(PBVH *pbvh);
+/* Texture painting. */
+void *BKE_pbvh_node_texture_paint_data_get(const PBVHNode *node);
+void BKE_pbvh_node_texture_paint_data_set(PBVHNode *node,
+ void *texture_paint_data,
+ PBVHNodeTexturePaintDataFreeFunc free_func);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 3ed3c7badc3..3c379aaa411 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -679,6 +679,7 @@ void BKE_pbvh_free(PBVH *pbvh)
if (node->bm_other_verts) {
BLI_gset_free(node->bm_other_verts, NULL);
}
+ BKE_pbvh_node_texture_paint_data_set(node, NULL, NULL);
}
}
@@ -3072,3 +3073,32 @@ void BKE_pbvh_respect_hide_set(PBVH *pbvh, bool respect_hide)
{
pbvh->respect_hide = respect_hide;
}
+
+/* -------------------------------------------------------------------- */
+/** \name Texture painting operations
+ * \{ */
+
+void *BKE_pbvh_node_texture_paint_data_get(const PBVHNode *node)
+{
+ BLI_assert(node->flag & PBVH_Leaf);
+ return node->texture_painting.data;
+}
+
+void BKE_pbvh_node_texture_paint_data_set(PBVHNode *node,
+ void *texture_paint_data,
+ PBVHNodeTexturePaintDataFreeFunc free_func)
+{
+ BLI_assert(node->flag & PBVH_Leaf);
+
+ if (node->texture_painting.data != NULL) {
+ node->texture_painting.free_func(node->texture_painting.data);
+ node->texture_painting.data = NULL;
+ node->texture_painting.free_func = NULL;
+ }
+
+ if (texture_paint_data != NULL) {
+ BLI_assert(free_func);
+ node->texture_painting.data = texture_paint_data;
+ node->texture_painting.free_func = free_func;
+ }
+}
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index 123a6b1b829..6b3108e8460 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -93,6 +93,7 @@ struct PBVHNode {
/* Used to store the brush color during a stroke and composite it over the original color */
PBVHColorBufferNode color_buffer;
+ PBVHTexturePaintingNode texture_painting;
};
typedef enum {
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index 41fdb37a005..55c90214ac1 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -65,7 +65,7 @@ set(SRC
sculpt_paint_color.c
sculpt_pose.c
sculpt_smooth.c
- sculpt_texture_paint_a.cc
+ sculpt_texture_paint_b.cc
sculpt_transform.c
sculpt_undo.c
sculpt_uv.c
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 525e1be5520..f6b334f2175 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -5041,6 +5041,14 @@ void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags)
multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED);
}
+ if (update_flags & SCULPT_UPDATE_TEXTURE) {
+ /* When using the texture paint brush only the texture changes. The Geometry and shading should
+ * not be touched.*/
+ SCULPT_flush_texture_paint(ob);
+ ED_region_tag_redraw(region);
+ return;
+ }
+
DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
/* Only current viewport matters, slower update for all viewports will
@@ -5256,6 +5264,9 @@ static void sculpt_stroke_update_step(bContext *C,
else if (ELEM(brush->sculpt_tool, SCULPT_TOOL_PAINT, SCULPT_TOOL_SMEAR)) {
SCULPT_flush_update_step(C, SCULPT_UPDATE_COLOR);
}
+ else if (brush->sculpt_tool == SCULPT_TOOL_TEXTURE_PAINT) {
+ SCULPT_flush_update_step(C, SCULPT_UPDATE_TEXTURE);
+ }
else {
SCULPT_flush_update_step(C, SCULPT_UPDATE_COORDS);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index ad4f13fc438..39aaf4d1276 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -43,6 +43,7 @@ typedef enum SculptUpdateType {
SCULPT_UPDATE_MASK = 1 << 1,
SCULPT_UPDATE_VISIBILITY = 1 << 2,
SCULPT_UPDATE_COLOR = 1 << 3,
+ SCULPT_UPDATE_TEXTURE = 1 << 4,
} SculptUpdateType;
typedef struct SculptCursorGeometryInfo {
@@ -1613,6 +1614,7 @@ void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in
/* Paint Brush. */
void SCULPT_do_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
void SCULPT_do_texture_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
+void SCULPT_flush_texture_paint(Object *ob);
/* Smear Brush. */
void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
diff --git a/source/blender/editors/sculpt_paint/sculpt_texture_paint_a.cc b/source/blender/editors/sculpt_paint/sculpt_texture_paint_a.cc
index d3e93574c1a..6e643cdd9b1 100644
--- a/source/blender/editors/sculpt_paint/sculpt_texture_paint_a.cc
+++ b/source/blender/editors/sculpt_paint/sculpt_texture_paint_a.cc
@@ -82,7 +82,6 @@ struct TexturePaintingUserData {
Object *ob;
Brush *brush;
PBVHNode **nodes;
- Vector<rctf> region_to_update;
};
static void do_task_cb_ex(void *__restrict userdata,
@@ -204,5 +203,9 @@ void SCULPT_do_texture_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int
BKE_image_release_ibuf(image, image_buffer, lock);
ss->mode.texture_paint.drawing_target = nullptr;
}
+
+void SCULPT_flush_texture_paint(Object *UNUSED(ob))
+{
+}
}
} // namespace blender::ed::sculpt_paint::texture_paint
diff --git a/source/blender/editors/sculpt_paint/sculpt_texture_paint_b.cc b/source/blender/editors/sculpt_paint/sculpt_texture_paint_b.cc
index d3e93574c1a..9ad8be1d8e1 100644
--- a/source/blender/editors/sculpt_paint/sculpt_texture_paint_b.cc
+++ b/source/blender/editors/sculpt_paint/sculpt_texture_paint_b.cc
@@ -37,6 +37,63 @@
namespace blender::ed::sculpt_paint::texture_paint {
+struct PixelData {
+ struct {
+ bool dirty : 1;
+ } flags;
+ int2 pixel_pos;
+ float3 local_pos;
+ float4 content;
+};
+
+struct NodeData {
+ struct {
+ bool dirty : 1;
+ } flags;
+
+ Vector<PixelData> pixels;
+ rcti dirty_region;
+
+ NodeData()
+ {
+ flags.dirty = false;
+ BLI_rcti_init_minmax(&dirty_region);
+ }
+
+ void init_pixels(Object *ob, PBVHNode *node, ImBuf *image_buffer);
+ void flush(ImBuf &image_buffer)
+ {
+ flags.dirty = false;
+ int pixels_flushed = 0;
+ for (PixelData &pixel : pixels) {
+ if (pixel.flags.dirty) {
+ const int pixel_offset = (pixel.pixel_pos[1] * image_buffer.x + pixel.pixel_pos[0]) * 4;
+ copy_v4_v4(&image_buffer.rect_float[pixel_offset], pixel.content);
+ pixel.flags.dirty = false;
+ pixels_flushed += 1;
+ }
+ }
+ printf("%s: %d pixels flushed\n", __func__, pixels_flushed);
+ }
+
+ void mark_region(Image &image, ImBuf &image_buffer)
+ {
+ printf("%s", __func__);
+ print_rcti_id(&dirty_region);
+ BKE_image_partial_update_mark_region(
+ &image, static_cast<ImageTile *>(image.tiles.first), &image_buffer, &dirty_region);
+ BLI_rcti_init_minmax(&dirty_region);
+ }
+
+ static void free_func(void *instance)
+ {
+ NodeData *node_data = static_cast<NodeData *>(instance);
+ MEM_delete(node_data);
+ }
+};
+
+namespace shaders {
+
using namespace imbuf::rasterizer;
struct VertexInput {
@@ -58,66 +115,110 @@ class VertexShader : public AbstractVertexShader<VertexInput, float3> {
}
};
-class FragmentShader : public AbstractFragmentShader<float3, float4> {
+struct FragmentOutput {
+ float3 local_pos;
+};
+
+class FragmentShader : public AbstractFragmentShader<float3, FragmentOutput> {
public:
- float4 color;
- const Brush *brush = nullptr;
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn;
+ ImBuf *image_buffer;
+ public:
void fragment(const FragmentInputType &input, FragmentOutputType *r_output) override
{
- copy_v4_v4(*r_output, color);
- float strength = sculpt_brush_test_sq_fn(&test, input) ?
- BKE_brush_curve_strength(brush, sqrtf(test.dist), test.radius) :
- 0.0f;
+ r_output->local_pos = input;
+ }
+};
+
+struct NodeDataPair {
+ ImBuf *image_buffer;
+ NodeData *node_data;
- (*r_output)[3] *= strength;
+ struct {
+ /* Rasterizer doesn't support glCoord yet, so for now we just store them in a runtime section.
+ */
+ int2 last_known_pixel_pos;
+ } runtime;
+};
+
+class AddPixel : public AbstractBlendMode<FragmentOutput, NodeDataPair> {
+ public:
+ void blend(NodeDataPair *dest, const FragmentOutput &source) const override
+ {
+ PixelData new_pixel;
+ new_pixel.local_pos = source.local_pos;
+ new_pixel.pixel_pos = dest->runtime.last_known_pixel_pos;
+ const int pixel_offset = new_pixel.pixel_pos[1] * dest->image_buffer->x +
+ new_pixel.pixel_pos[0];
+ new_pixel.content = float4(dest->image_buffer->rect_float[pixel_offset * 4]);
+ new_pixel.flags.dirty = false;
+
+ dest->node_data->pixels.append(new_pixel);
+ dest->runtime.last_known_pixel_pos[0] += 1;
}
};
-using RasterizerType = Rasterizer<VertexShader, FragmentShader, AlphaBlendMode>;
+class NodeDataDrawingTarget : public AbstractDrawingTarget<NodeDataPair, NodeDataPair> {
+ private:
+ NodeDataPair *active_ = nullptr;
-struct TexturePaintingUserData {
- Object *ob;
- Brush *brush;
- PBVHNode **nodes;
- Vector<rctf> region_to_update;
+ public:
+ uint64_t get_width() const
+ {
+ return active_->image_buffer->x;
+ }
+ uint64_t get_height() const
+ {
+ return active_->image_buffer->y;
+ };
+ NodeDataPair *get_pixel_ptr(uint64_t x, uint64_t y)
+ {
+ active_->runtime.last_known_pixel_pos = int2(x, y);
+ return active_;
+ };
+ int64_t get_pixel_stride() const
+ {
+ return 0;
+ };
+ bool has_active_target() const
+ {
+ return active_ != nullptr;
+ }
+ void activate(NodeDataPair *instance)
+ {
+ active_ = instance;
+ };
+ void deactivate()
+ {
+ active_ = nullptr;
+ }
};
-static void do_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- TexturePaintingUserData *data = static_cast<TexturePaintingUserData *>(userdata);
- Object *ob = data->ob;
- SculptSession *ss = ob->sculpt;
- const Brush *brush = data->brush;
- ImBuf *drawing_target = ss->mode.texture_paint.drawing_target;
- RasterizerType rasterizer;
+using RasterizerType = Rasterizer<VertexShader, FragmentShader, AddPixel, NodeDataDrawingTarget>;
+
+} // namespace shaders
+void NodeData::init_pixels(Object *ob, PBVHNode *node, ImBuf *image_buffer)
+{
Mesh *mesh = static_cast<Mesh *>(ob->data);
MLoopUV *ldata_uv = static_cast<MLoopUV *>(CustomData_get_layer(&mesh->ldata, CD_MLOOPUV));
if (ldata_uv == nullptr) {
return;
}
- rasterizer.activate_drawing_target(drawing_target);
- rasterizer.vertex_shader().image_size = float2(drawing_target->x, drawing_target->y);
- srgb_to_linearrgb_v3_v3(rasterizer.fragment_shader().color, brush->rgb);
- FragmentShader &fragment_shader = rasterizer.fragment_shader();
- fragment_shader.color[3] = 1.0f;
- fragment_shader.brush = brush;
- fragment_shader.sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &fragment_shader.test, brush->falloff_shape);
-
- PBVHVertexIter vd;
+ shaders::RasterizerType rasterizer;
+ shaders::NodeDataPair node_data_pair;
+ rasterizer.vertex_shader().image_size = float2(image_buffer->x, image_buffer->y);
+ rasterizer.fragment_shader().image_buffer = image_buffer;
+ node_data_pair.node_data = this;
+ node_data_pair.image_buffer = image_buffer;
+ rasterizer.activate_drawing_target(&node_data_pair);
+ SculptSession *ss = ob->sculpt;
MVert *mvert = SCULPT_mesh_deformed_mverts_get(ss);
- rctf &region_to_update = data->region_to_update[n];
- BLI_rctf_init_minmax(&region_to_update);
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
MeshElemMap *vert_map = &ss->pmap[vd.index];
for (int j = 0; j < ss->pmap[vd.index].count; j++) {
const MPoly *p = &ss->mpoly[vert_map->indices[j]];
@@ -125,12 +226,7 @@ static void do_task_cb_ex(void *__restrict userdata,
continue;
}
- float poly_center[3];
const MLoop *loopstart = &ss->mloop[p->loopstart];
- BKE_mesh_calc_poly_center(p, &ss->mloop[p->loopstart], mvert, poly_center);
- if (!fragment_shader.sculpt_brush_test_sq_fn(&fragment_shader.test, poly_center)) {
- continue;
- }
for (int triangle = 0; triangle < p->totloop - 2; triangle++) {
const int v1_index = loopstart[0].v;
@@ -140,47 +236,104 @@ static void do_task_cb_ex(void *__restrict userdata,
const int v2_loop_index = p->loopstart + triangle + 1;
const int v3_loop_index = p->loopstart + triangle + 2;
- VertexInput v1(mvert[v1_index].co, ldata_uv[v1_loop_index].uv);
- VertexInput v2(mvert[v2_index].co, ldata_uv[v2_loop_index].uv);
- VertexInput v3(mvert[v3_index].co, ldata_uv[v3_loop_index].uv);
+ shaders::VertexInput v1(mvert[v1_index].co, ldata_uv[v1_loop_index].uv);
+ shaders::VertexInput v2(mvert[v2_index].co, ldata_uv[v2_loop_index].uv);
+ shaders::VertexInput v3(mvert[v3_index].co, ldata_uv[v3_loop_index].uv);
rasterizer.draw_triangle(v1, v2, v3);
-
- BLI_rctf_do_minmax_v(&region_to_update, v1.uv);
- BLI_rctf_do_minmax_v(&region_to_update, v2.uv);
- BLI_rctf_do_minmax_v(&region_to_update, v3.uv);
}
}
}
BKE_pbvh_vertex_iter_end;
-
rasterizer.deactivate_drawing_target();
}
+struct TexturePaintingUserData {
+ Object *ob;
+ Brush *brush;
+ PBVHNode **nodes;
+};
+
+static void do_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ TexturePaintingUserData *data = static_cast<TexturePaintingUserData *>(userdata);
+ Object *ob = data->ob;
+ SculptSession *ss = ob->sculpt;
+ const Brush *brush = data->brush;
+ PBVHNode *node = data->nodes[n];
+ NodeData *node_data = static_cast<NodeData *>(BKE_pbvh_node_texture_paint_data_get(node));
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, brush->falloff_shape);
+
+ for (PixelData &pixel : node_data->pixels) {
+ if (!sculpt_brush_test_sq_fn(&test, pixel.local_pos)) {
+ continue;
+ }
+ const float falloff_strength = BKE_brush_curve_strength(brush, sqrtf(test.dist), test.radius);
+ interp_v3_v3v3(pixel.content, pixel.content, brush->rgb, falloff_strength);
+ pixel.flags.dirty = true;
+ BLI_rcti_do_minmax_v(&node_data->dirty_region, pixel.pixel_pos);
+ }
+ node_data->flags.dirty = true;
+}
+
+struct ImageData {
+ void *lock = nullptr;
+ Image *image = nullptr;
+ ImageUser *image_user = nullptr;
+ ImBuf *image_buffer = nullptr;
+
+ ~ImageData()
+ {
+ BKE_image_release_ibuf(image, image_buffer, lock);
+ }
+
+ static bool init_active_image(Object *ob, ImageData *r_image_data)
+ {
+ ED_object_get_active_image(
+ ob, 1, &r_image_data->image, &r_image_data->image_user, nullptr, nullptr);
+ if (r_image_data->image == nullptr) {
+ return false;
+ }
+ r_image_data->image_buffer = BKE_image_acquire_ibuf(
+ r_image_data->image, r_image_data->image_user, &r_image_data->lock);
+ if (r_image_data->image_buffer == nullptr) {
+ return false;
+ }
+ return true;
+ }
+};
+
extern "C" {
void SCULPT_do_texture_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- void *lock;
- Image *image;
- ImageUser *image_user;
-
- ED_object_get_active_image(ob, 1, &image, &image_user, nullptr, nullptr);
- if (image == nullptr) {
+ ImageData image_data;
+ if (!ImageData::init_active_image(ob, &image_data)) {
return;
}
- ImBuf *image_buffer = BKE_image_acquire_ibuf(image, image_user, &lock);
- if (image_buffer == nullptr) {
- return;
+
+ for (int n = 0; n < totnode; n++) {
+ PBVHNode *node = nodes[n];
+ NodeData *data = static_cast<NodeData *>(BKE_pbvh_node_texture_paint_data_get(node));
+ if (data == nullptr) {
+ NodeData *node_data = MEM_new<NodeData>(__func__);
+ node_data->init_pixels(ob, node, image_data.image_buffer);
+ BKE_pbvh_node_texture_paint_data_set(node, node_data, NodeData::free_func);
+ }
}
- ss->mode.texture_paint.drawing_target = image_buffer;
+
+ ss->mode.texture_paint.drawing_target = image_data.image_buffer;
TexturePaintingUserData data = {nullptr};
data.ob = ob;
data.brush = brush;
data.nodes = nodes;
- data.region_to_update.resize(totnode);
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
@@ -189,20 +342,34 @@ void SCULPT_do_texture_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int
BLI_task_parallel_range(0, totnode, &data, do_task_cb_ex, &settings);
TIMEIT_END(texture_painting);
- for (int i = 0; i < totnode; i++) {
- rcti region_to_update;
- region_to_update.xmin = data.region_to_update[i].xmin * image_buffer->x;
- region_to_update.xmax = data.region_to_update[i].xmax * image_buffer->x;
- region_to_update.ymin = data.region_to_update[i].ymin * image_buffer->y;
- region_to_update.ymax = data.region_to_update[i].ymax * image_buffer->y;
+ ss->mode.texture_paint.drawing_target = nullptr;
+}
- /* TODO: Tiled images. */
- BKE_image_partial_update_mark_region(
- image, static_cast<ImageTile *>(image->tiles.first), image_buffer, &region_to_update);
+void SCULPT_flush_texture_paint(Object *ob)
+{
+ ImageData image_data;
+ if (!ImageData::init_active_image(ob, &image_data)) {
+ return;
}
- BKE_image_release_ibuf(image, image_buffer, lock);
- ss->mode.texture_paint.drawing_target = nullptr;
+ SculptSession *ss = ob->sculpt;
+ PBVHNode **nodes;
+ int totnode;
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+ for (int n = 0; n < totnode; n++) {
+ PBVHNode *node = nodes[n];
+ NodeData *data = static_cast<NodeData *>(BKE_pbvh_node_texture_paint_data_get(node));
+ if (data == nullptr) {
+ continue;
+ }
+
+ if (data->flags.dirty) {
+ data->flush(*image_data.image_buffer);
+ data->mark_region(*image_data.image, *image_data.image_buffer);
+ }
+ }
+
+ MEM_freeN(nodes);
}
}
} // namespace blender::ed::sculpt_paint::texture_paint
diff --git a/source/blender/imbuf/IMB_rasterizer.hh b/source/blender/imbuf/IMB_rasterizer.hh
index 187d980fbab..24306f4514f 100644
--- a/source/blender/imbuf/IMB_rasterizer.hh
+++ b/source/blender/imbuf/IMB_rasterizer.hh
@@ -269,7 +269,8 @@ class Rasterizer {
using VertexOutputType = typename VertexShader::VertexOutputType;
using FragmentInputType = typename FragmentShader::FragmentInputType;
using FragmentOutputType = typename FragmentShader::FragmentOutputType;
- using TargetBufferType = typename DrawingTarget::InnerType;
+ using TargetBufferType = typename DrawingTarget::BufferType;
+ using PixelType = typename DrawingTarget::PixelType;
/** Check if the vertex shader and the fragment shader can be linked together. */
static_assert(std::is_same_v<InterfaceInnerType, FragmentInputType>);
@@ -684,7 +685,7 @@ class Rasterizer {
void render_rasterline(const RasterlineType &rasterline)
{
FragmentInputType data = rasterline.start_data;
- float *pixel_ptr = drawing_target_.get_pixel_ptr(rasterline.start_x, rasterline.y);
+ PixelType *pixel_ptr = drawing_target_.get_pixel_ptr(rasterline.start_x, rasterline.y);
for (uint32_t x = rasterline.start_x; x < rasterline.end_x; x++) {
FragmentOutputType fragment_out;
diff --git a/source/blender/imbuf/intern/rasterizer_target.hh b/source/blender/imbuf/intern/rasterizer_target.hh
index 25830b4006a..d181d9e1e06 100644
--- a/source/blender/imbuf/intern/rasterizer_target.hh
+++ b/source/blender/imbuf/intern/rasterizer_target.hh
@@ -17,19 +17,20 @@ namespace blender::imbuf::rasterizer {
* An abstract implementation of a drawing target. Will make it possible to switch to other render
* targets then only ImBuf types.
*/
-template<typename Inner> class AbstractDrawingTarget {
+template<typename Buffer, typename Pixel = float> class AbstractDrawingTarget {
public:
- using InnerType = Inner;
+ using BufferType = Buffer;
+ using PixelType = Pixel;
virtual uint64_t get_width() const = 0;
virtual uint64_t get_height() const = 0;
- virtual float *get_pixel_ptr(uint64_t x, uint64_t y) = 0;
+ virtual PixelType *get_pixel_ptr(uint64_t x, uint64_t y) = 0;
virtual int64_t get_pixel_stride() const = 0;
virtual bool has_active_target() const = 0;
- virtual void activate(Inner *instance) = 0;
+ virtual void activate(BufferType *instance) = 0;
virtual void deactivate() = 0;
};
-class ImageBufferDrawingTarget : public AbstractDrawingTarget<ImBuf> {
+class ImageBufferDrawingTarget : public AbstractDrawingTarget<ImBuf, float> {
private:
ImBuf *image_buffer_ = nullptr;