Image: support storing full image buffers for each undo step
Update image undo to store buffers for each step: - Undo buffers share tiles to avoid using too much memory. - Undo support for different sized buffers allowing operations such as crop or resize. - Paint tiles have been split into separate API/storage. - Painting speed wont be impacted significantly since storing the extra tiles is done after the stroke & only for the first undo step. Resolves T61263, see D5939 for details.
This commit is contained in:
parent
bdd142bc02
commit
151cc02b6f
Notes:
blender-bot
2023-02-14 07:31:34 +01:00
Referenced by commit 5b18997543
, T71094: anchored & drag-dot brushes paint continuously
Referenced by issue #83806, Undo - Current Status and Important Fixes Needed
Referenced by issue #61263, Undo steps with texture paint break across memfile steps
|
@ -42,6 +42,10 @@ void ED_imapaint_bucket_fill(struct bContext *C, float color[3], struct wmOperat
|
|||
|
||||
/* paint_image_undo.c */
|
||||
void ED_image_undo_push_begin(const char *name, int paint_mode);
|
||||
void ED_image_undo_push_begin_with_image(const char *name,
|
||||
struct Image *image,
|
||||
struct ImBuf *ibuf);
|
||||
|
||||
void ED_image_undo_push_end(void);
|
||||
void ED_image_undo_restore(struct UndoStep *us);
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ set(INC
|
|||
../../render/extern/include
|
||||
../../windowmanager
|
||||
../../../../intern/atomic
|
||||
../../../../intern/clog
|
||||
../../../../intern/glew-mx
|
||||
../../../../intern/guardedalloc
|
||||
)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2765,8 +2765,7 @@ static int image_invert_exec(bContext *C, wmOperator *op)
|
|||
Image *ima = image_from_context(C);
|
||||
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
|
||||
SpaceImage *sima = CTX_wm_space_image(C);
|
||||
/* undo is supported only on image paint mode currently */
|
||||
bool support_undo = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
|
||||
const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
|
||||
|
||||
/* flags indicate if this channel should be inverted */
|
||||
const bool r = RNA_boolean_get(op->ptr, "invert_r");
|
||||
|
@ -2781,14 +2780,12 @@ static int image_invert_exec(bContext *C, wmOperator *op)
|
|||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
if (support_undo) {
|
||||
ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D);
|
||||
/* not strictly needed, because we only imapaint_dirty_region to invalidate all tiles
|
||||
* but better do this right in case someone copies this for a tool that uses partial
|
||||
* redraw better */
|
||||
ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf);
|
||||
|
||||
if (is_paint) {
|
||||
ED_imapaint_clear_partial_redraw();
|
||||
ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
|
||||
}
|
||||
|
||||
/* TODO: make this into an IMB_invert_channels(ibuf,r,g,b,a) method!? */
|
||||
if (ibuf->rect_float) {
|
||||
|
||||
|
@ -2842,9 +2839,7 @@ static int image_invert_exec(bContext *C, wmOperator *op)
|
|||
ibuf->userflags |= IB_MIPMAP_INVALID;
|
||||
}
|
||||
|
||||
if (support_undo) {
|
||||
ED_image_undo_push_end();
|
||||
}
|
||||
ED_image_undo_push_end();
|
||||
|
||||
/* force GPU reupload, all image is invalid */
|
||||
GPU_free_image(ima);
|
||||
|
@ -2880,7 +2875,7 @@ void IMAGE_OT_invert(wmOperatorType *ot)
|
|||
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
ot->flag = OPTYPE_REGISTER;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -228,6 +228,8 @@ void IMB_blend_color_float(float dst[4],
|
|||
|
||||
void IMB_rect_crop(struct ImBuf *ibuf, const struct rcti *crop);
|
||||
|
||||
void IMB_rect_size_set(struct ImBuf *ibuf, const uint size[2]);
|
||||
|
||||
void IMB_rectclip(struct ImBuf *dbuf,
|
||||
const struct ImBuf *sbuf,
|
||||
int *destx,
|
||||
|
|
|
@ -279,6 +279,45 @@ void IMB_rect_crop(ImBuf *ibuf, const rcti *crop)
|
|||
ibuf->y = size_dst[1];
|
||||
}
|
||||
|
||||
/** Re-alloc buffers at a new size */
|
||||
|
||||
static void rect_realloc_4bytes(void **buf_p, const uint size[2])
|
||||
{
|
||||
if (*buf_p == NULL) {
|
||||
return;
|
||||
}
|
||||
MEM_freeN(*buf_p);
|
||||
*buf_p = MEM_mallocN(sizeof(uint) * size[0] * size[1], __func__);
|
||||
}
|
||||
|
||||
static void rect_realloc_16bytes(void **buf_p, const uint size[2])
|
||||
{
|
||||
if (*buf_p == NULL) {
|
||||
return;
|
||||
}
|
||||
MEM_freeN(*buf_p);
|
||||
*buf_p = MEM_mallocN(sizeof(uint[4]) * size[0] * size[1], __func__);
|
||||
}
|
||||
|
||||
/**
|
||||
* In-place size setting (caller must fill in buffer contents).
|
||||
*/
|
||||
void IMB_rect_size_set(ImBuf *ibuf, const uint size[2])
|
||||
{
|
||||
BLI_assert(size[0] > 0 && size[0] > 0);
|
||||
if ((size[0] == ibuf->x) && (size[1] == ibuf->y)) {
|
||||
return;
|
||||
}
|
||||
|
||||
rect_realloc_4bytes((void **)&ibuf->rect, size);
|
||||
rect_realloc_4bytes((void **)&ibuf->zbuf, size);
|
||||
rect_realloc_4bytes((void **)&ibuf->zbuf_float, size);
|
||||
rect_realloc_16bytes((void **)&ibuf->rect_float, size);
|
||||
|
||||
ibuf->x = size[0];
|
||||
ibuf->y = size[1];
|
||||
}
|
||||
|
||||
/* clipping */
|
||||
|
||||
void IMB_rectclip(ImBuf *dbuf,
|
||||
|
|
Loading…
Reference in New Issue