Fix T74425: Cannot texture paint an images sequence anymore

Caused by the introduction of UDIM (rBc30d6571bb47).

We need to make sure the tiles ImageUser is set up correctly [especially
the framenr], otherwise BKE_image_acquire_ibuf() and friends will fail
to find the correct ImBuf.

Also instead of initializing a minimal BKE_imageuser_default, now use
an appropriate ImageUser if avaliable and pass this around (instead of
just the tile_number). 2D painting can reuse the Image Editor ImageUser,
for 3D painting we still rely on a default ImageUser in most places, but
at least set the framenr correctly].

This also fixes crashes when doing image operations such as inverting or
resizing on images in a sequence in the Image Editor.

This also fixes color sampling (S) from the 3DView going wrong for image
sequences (would fallback to OpenGL sampling because an ImBuf could not
be found).

Maniphest Tasks: T74425

Differential Revision: https://developer.blender.org/D7022
This commit is contained in:
Philipp Oeser 2020-03-04 14:40:21 +01:00
parent 212660f467
commit ca717f0489
Notes: blender-bot 2023-02-13 23:20:36 +01:00
Referenced by issue #74425, Can't texture paint an images sequence anymore
Referenced by issue #74274, Blender 2.82a proposed revisions
7 changed files with 53 additions and 44 deletions

View File

@ -27,6 +27,7 @@ extern "C" {
struct ImBuf;
struct Image;
struct ImageUser;
struct UndoStep;
struct UndoType;
struct bContext;
@ -42,7 +43,7 @@ void ED_keymap_paint(struct wmKeyConfig *keyconf);
void ED_imapaint_clear_partial_redraw(void);
void ED_imapaint_dirty_region(struct Image *ima,
struct ImBuf *ibuf,
int tile_number,
struct ImageUser *iuser,
int x,
int y,
int w,
@ -58,7 +59,7 @@ 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,
int tile_number);
struct ImageUser *iuser);
void ED_image_undo_push_end(void);
void ED_image_undo_restore(struct UndoStep *us);
@ -68,7 +69,7 @@ void ED_image_undosys_type(struct UndoType *ut);
void *ED_image_paint_tile_find(struct ListBase *undo_tiles,
struct Image *ima,
struct ImBuf *ibuf,
int tile_number,
struct ImageUser *iuser,
int x_tile,
int y_tile,
unsigned short **r_mask,
@ -77,7 +78,7 @@ void *ED_image_paint_tile_push(struct ListBase *undo_tiles,
struct Image *ima,
struct ImBuf *ibuf,
struct ImBuf **tmpibuf,
int tile_number,
struct ImageUser *iuser,
int x_tile,
int y_tile,
unsigned short **r_mask,

View File

@ -120,7 +120,7 @@ void imapaint_region_tiles(
}
void ED_imapaint_dirty_region(
Image *ima, ImBuf *ibuf, int tile_number, int x, int y, int w, int h, bool find_old)
Image *ima, ImBuf *ibuf, ImageUser *iuser, int x, int y, int w, int h, bool find_old)
{
ImBuf *tmpibuf = NULL;
int tilex, tiley, tilew, tileh, tx, ty;
@ -153,7 +153,7 @@ void ED_imapaint_dirty_region(
for (ty = tiley; ty <= tileh; ty++) {
for (tx = tilex; tx <= tilew; tx++) {
ED_image_paint_tile_push(
undo_tiles, ima, ibuf, &tmpibuf, tile_number, tx, ty, NULL, NULL, false, find_old);
undo_tiles, ima, ibuf, &tmpibuf, iuser, tx, ty, NULL, NULL, false, find_old);
}
}

View File

@ -1335,11 +1335,11 @@ static void paint_2d_do_making_brush(ImagePaintState *s,
if (tile->canvas->rect_float) {
tmpbuf.rect_float = ED_image_paint_tile_find(
undo_tiles, s->image, tile->canvas, tile->iuser.tile, tx, ty, &mask, false);
undo_tiles, s->image, tile->canvas, &tile->iuser, tx, ty, &mask, false);
}
else {
tmpbuf.rect = ED_image_paint_tile_find(
undo_tiles, s->image, tile->canvas, tile->iuser.tile, tx, ty, &mask, false);
undo_tiles, s->image, tile->canvas, &tile->iuser, tx, ty, &mask, false);
}
IMB_rectblend(tile->canvas,
@ -1448,7 +1448,7 @@ static int paint_2d_op(void *state,
for (a = 0; a < tot; a++) {
ED_imapaint_dirty_region(s->image,
canvas,
tile->iuser.tile,
&tile->iuser,
region[a].destx,
region[a].desty,
region[a].width,
@ -1667,6 +1667,7 @@ void paint_2d_stroke(void *ps,
void *paint_2d_new_stroke(bContext *C, wmOperator *op, int mode)
{
Scene *scene = CTX_data_scene(C);
SpaceImage *sima = CTX_wm_space_image(C);
ToolSettings *settings = scene->toolsettings;
Brush *brush = BKE_paint_brush(&settings->imapaint.paint);
@ -1697,7 +1698,7 @@ void *paint_2d_new_stroke(bContext *C, wmOperator *op, int mode)
s->num_tiles = BLI_listbase_count(&s->image->tiles);
s->tiles = MEM_callocN(sizeof(ImagePaintTile) * s->num_tiles, "ImagePaintTile");
for (int i = 0; i < s->num_tiles; i++) {
BKE_imageuser_default(&s->tiles[i].iuser);
s->tiles[i].iuser = sima->iuser;
}
s->tiles[0].iuser.ok = true;
@ -1941,7 +1942,7 @@ void paint_2d_bucket_fill(const bContext *C,
if (!mouse_final || !br) {
/* first case, no image UV, fill the whole image */
ED_imapaint_dirty_region(ima, ibuf, tile_number, 0, 0, ibuf->x, ibuf->y, false);
ED_imapaint_dirty_region(ima, ibuf, iuser, 0, 0, ibuf->x, ibuf->y, false);
if (do_float) {
for (x_px = 0; x_px < ibuf->x; x_px++) {
@ -1984,7 +1985,7 @@ void paint_2d_bucket_fill(const bContext *C,
}
/* change image invalidation method later */
ED_imapaint_dirty_region(ima, ibuf, tile_number, 0, 0, ibuf->x, ibuf->y, false);
ED_imapaint_dirty_region(ima, ibuf, iuser, 0, 0, ibuf->x, ibuf->y, false);
stack = BLI_stack_new(sizeof(size_t), __func__);
touched = BLI_BITMAP_NEW(((size_t)ibuf->x) * ibuf->y, "bucket_fill_bitmap");
@ -2158,7 +2159,7 @@ void paint_2d_gradient_fill(
do_float = (ibuf->rect_float != NULL);
/* this will be substituted by something else when selection is available */
ED_imapaint_dirty_region(ima, ibuf, tile_number, 0, 0, ibuf->x, ibuf->y, false);
ED_imapaint_dirty_region(ima, ibuf, iuser, 0, 0, ibuf->x, ibuf->y, false);
if (do_float) {
for (x_px = 0; x_px < ibuf->x; x_px++) {

View File

@ -744,9 +744,11 @@ static bool project_paint_PickColor(const ProjPaintState *ps,
ima = project_paint_face_paint_image(ps, tri_index);
/** we must have got the imbuf before getting here. */
int tile_number = project_paint_face_paint_tile(ima, lt_tri_uv[0]);
/* XXX get appropriate ImageUser instead */
ImageUser iuser;
BKE_imageuser_default(&iuser);
iuser.tile = tile_number;
iuser.framenr = ima->lastframe;
ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
if (ibuf == NULL) {
return false;
@ -1839,7 +1841,7 @@ static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty)
pjIma->ima,
pjIma->ibuf,
tinf->tmpibuf,
pjIma->iuser.tile,
&pjIma->iuser,
tx,
ty,
&pjIma->maskRect[tile_index],
@ -1852,7 +1854,7 @@ static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty)
pjIma->ima,
pjIma->ibuf,
tinf->tmpibuf,
pjIma->iuser.tile,
&pjIma->iuser,
tx,
ty,
NULL,
@ -4265,7 +4267,7 @@ static bool project_paint_winclip(const ProjPaintState *ps, const ProjPaintFaceC
typedef struct PrepareImageEntry {
struct PrepareImageEntry *next, *prev;
Image *ima;
int tile;
ImageUser iuser;
} PrepareImageEntry;
static void project_paint_build_proj_ima(ProjPaintState *ps,
@ -4280,9 +4282,7 @@ static void project_paint_build_proj_ima(ProjPaintState *ps,
projIma = ps->projImages = BLI_memarena_alloc(arena, sizeof(ProjPaintImage) * ps->image_tot);
for (entry = used_images->first, i = 0; entry; entry = entry->next, i++, projIma++) {
memset(&projIma->iuser, 0, sizeof(ImageUser));
BKE_imageuser_default(&projIma->iuser);
projIma->iuser.tile = entry->tile;
projIma->iuser = entry->iuser;
int size;
projIma->ima = entry->ima;
projIma->touch = 0;
@ -4434,19 +4434,21 @@ static void project_paint_prepare_all_faces(ProjPaintState *ps,
if (tpage_last != tpage || tile_last != tile) {
image_index = 0;
for (PrepareImageEntry *e = used_images.first; e; e = e->next, image_index++) {
if (e->ima == tpage && e->tile == tile) {
if (e->ima == tpage && e->iuser.tile == tile) {
break;
}
}
if (image_index == ps->image_tot) {
/* XXX get appropriate ImageUser instead */
ImageUser iuser;
BKE_imageuser_default(&iuser);
iuser.tile = tile;
iuser.framenr = tpage->lastframe;
if (BKE_image_has_ibuf(tpage, &iuser)) {
PrepareImageEntry *e = MEM_callocN(sizeof(PrepareImageEntry), "PrepareImageEntry");
e->ima = tpage;
e->tile = tile;
e->iuser = iuser;
BLI_addtail(&used_images, e);
ps->image_tot++;
}

View File

@ -518,8 +518,10 @@ void paint_sample_color(
if (image) {
float uv[2];
float u, v;
/* XXX get appropriate ImageUser instead */
ImageUser iuser;
BKE_imageuser_default(&iuser);
iuser.framenr = image->lastframe;
imapaint_pick_uv(me_eval, scene, ob_eval, faceindex, mval, uv);

View File

@ -2751,7 +2751,7 @@ static int image_invert_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, 0);
ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &sima->iuser);
if (is_paint) {
ED_imapaint_clear_partial_redraw();
@ -2895,7 +2895,7 @@ static int image_scale_exec(bContext *C, wmOperator *op)
RNA_property_int_set_array(op->ptr, prop, size);
}
ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, 0);
ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &sima->iuser);
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
IMB_scaleImBuf(ibuf, size[0], size[1]);

View File

@ -107,7 +107,11 @@ typedef struct PaintTile {
struct PaintTile *next, *prev;
Image *image;
ImBuf *ibuf;
int tile_number;
/* For 2D image painting the ImageUser uses most of the values.
* Even though views and passes are stored they are currently not supported for painting.
* For 3D projection painting this only uses a tile & frame number.
* The scene pointer must be cleared (or temporarily set it as needed, but leave cleared). */
ImageUser iuser;
union {
float *fp;
uint *uint;
@ -149,7 +153,7 @@ static void ptile_invalidate_list(ListBase *paint_tiles)
void *ED_image_paint_tile_find(ListBase *paint_tiles,
Image *image,
ImBuf *ibuf,
int tile_number,
ImageUser *iuser,
int x_tile,
int y_tile,
ushort **r_mask,
@ -157,7 +161,7 @@ void *ED_image_paint_tile_find(ListBase *paint_tiles,
{
for (PaintTile *ptile = paint_tiles->first; ptile; ptile = ptile->next) {
if (ptile->x_tile == x_tile && ptile->y_tile == y_tile) {
if (ptile->image == image && ptile->ibuf == ibuf && ptile->tile_number == tile_number) {
if (ptile->image == image && ptile->ibuf == ibuf && ptile->iuser.tile == iuser->tile) {
if (r_mask) {
/* allocate mask if requested. */
if (!ptile->mask) {
@ -180,7 +184,7 @@ void *ED_image_paint_tile_push(ListBase *paint_tiles,
Image *image,
ImBuf *ibuf,
ImBuf **tmpibuf,
int tile_number,
ImageUser *iuser,
int x_tile,
int y_tile,
ushort **r_mask,
@ -195,7 +199,7 @@ void *ED_image_paint_tile_push(ListBase *paint_tiles,
/* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */
if (find_prev) {
void *data = ED_image_paint_tile_find(
paint_tiles, image, ibuf, tile_number, x_tile, y_tile, r_mask, true);
paint_tiles, image, ibuf, iuser, x_tile, y_tile, r_mask, true);
if (data) {
return data;
}
@ -209,7 +213,8 @@ void *ED_image_paint_tile_push(ListBase *paint_tiles,
ptile->image = image;
ptile->ibuf = ibuf;
ptile->tile_number = tile_number;
ptile->iuser = *iuser;
ptile->iuser.scene = NULL;
ptile->x_tile = x_tile;
ptile->y_tile = y_tile;
@ -264,10 +269,7 @@ static void ptile_restore_runtime_list(ListBase *paint_tiles)
for (PaintTile *ptile = paint_tiles->first; ptile; ptile = ptile->next) {
Image *image = ptile->image;
ImageUser iuser;
BKE_imageuser_default(&iuser);
iuser.tile = ptile->tile_number;
ImBuf *ibuf = BKE_image_acquire_ibuf(image, &iuser, NULL);
ImBuf *ibuf = BKE_image_acquire_ibuf(image, &ptile->iuser, NULL);
const bool has_float = (ibuf->rect_float != NULL);
if (has_float) {
@ -659,22 +661,23 @@ static UndoImageHandle *uhandle_lookup(ListBase *undo_handles, const Image *imag
return NULL;
}
static UndoImageHandle *uhandle_add(ListBase *undo_handles, Image *image, int tile_number)
static UndoImageHandle *uhandle_add(ListBase *undo_handles, Image *image, ImageUser *iuser)
{
BLI_assert(uhandle_lookup(undo_handles, image, tile_number) == NULL);
BLI_assert(uhandle_lookup(undo_handles, image, iuser->tile) == NULL);
UndoImageHandle *uh = MEM_callocN(sizeof(*uh), __func__);
uh->image_ref.ptr = image;
uh->iuser = *iuser;
BLI_assert(uh->iuser.scene == NULL);
uh->iuser.ok = 1;
uh->iuser.tile = tile_number;
BLI_addtail(undo_handles, uh);
return uh;
}
static UndoImageHandle *uhandle_ensure(ListBase *undo_handles, Image *image, int tile_number)
static UndoImageHandle *uhandle_ensure(ListBase *undo_handles, Image *image, ImageUser *iuser)
{
UndoImageHandle *uh = uhandle_lookup(undo_handles, image, tile_number);
UndoImageHandle *uh = uhandle_lookup(undo_handles, image, iuser->tile);
if (uh == NULL) {
uh = uhandle_add(undo_handles, image, tile_number);
uh = uhandle_add(undo_handles, image, iuser);
}
return uh;
}
@ -779,7 +782,7 @@ static bool image_undosys_step_encode(struct bContext *C,
/* Initialize undo tiles from ptiles (if they exist). */
for (PaintTile *ptile = us->paint_tiles.first, *ptile_next; ptile; ptile = ptile_next) {
if (ptile->valid) {
UndoImageHandle *uh = uhandle_ensure(&us->handles, ptile->image, ptile->tile_number);
UndoImageHandle *uh = uhandle_ensure(&us->handles, ptile->image, &ptile->iuser);
UndoImageBuf *ubuf_pre = uhandle_ensure_ubuf(uh, ptile->image, ptile->ibuf);
UndoImageTile *utile = MEM_callocN(sizeof(*utile), "UndoImageTile");
@ -1047,12 +1050,12 @@ void ED_image_undo_push_begin(const char *name, int paint_mode)
void ED_image_undo_push_begin_with_image(const char *name,
Image *image,
ImBuf *ibuf,
int tile_number)
ImageUser *iuser)
{
ImageUndoStep *us = image_undo_push_begin(name, PAINT_MODE_TEXTURE_2D);
BLI_assert(BKE_image_get_tile(image, tile_number));
UndoImageHandle *uh = uhandle_ensure(&us->handles, image, tile_number);
BLI_assert(BKE_image_get_tile(image, iuser->tile));
UndoImageHandle *uh = uhandle_ensure(&us->handles, image, iuser);
UndoImageBuf *ubuf_pre = uhandle_ensure_ubuf(uh, image, ibuf);
BLI_assert(ubuf_pre->post == NULL);
@ -1061,7 +1064,7 @@ void ED_image_undo_push_begin_with_image(const char *name,
us_reference = (ImageUndoStep *)us_reference->step.prev;
}
UndoImageBuf *ubuf_reference = (us_reference ? ubuf_lookup_from_reference(
us_reference, image, tile_number, ubuf_pre) :
us_reference, image, iuser->tile, ubuf_pre) :
NULL);
if (ubuf_reference) {