Blender  V2.93
image_undo.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * along with this program; if not, write to the Free Software Foundation,
13  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
14  */
15 
33 #include "CLG_log.h"
34 
35 #include "MEM_guardedalloc.h"
36 
37 #include "BLI_blenlib.h"
38 #include "BLI_math.h"
39 #include "BLI_threads.h"
40 #include "BLI_utildefines.h"
41 
42 #include "DNA_image_types.h"
43 #include "DNA_object_types.h"
44 #include "DNA_screen_types.h"
45 #include "DNA_space_types.h"
47 
48 #include "IMB_imbuf.h"
49 #include "IMB_imbuf_types.h"
50 
51 #include "BKE_context.h"
52 #include "BKE_image.h"
53 #include "BKE_paint.h"
54 #include "BKE_undo_system.h"
55 
56 #include "DEG_depsgraph.h"
57 
58 #include "ED_object.h"
59 #include "ED_paint.h"
60 #include "ED_undo.h"
61 #include "ED_util.h"
62 
63 #include "WM_api.h"
64 
65 static CLG_LogRef LOG = {"ed.image.undo"};
66 
67 /* -------------------------------------------------------------------- */
71 /* This is a non-global static resource,
72  * Maybe it should be exposed as part of the
73  * paint operation, but for now just give a public interface */
75 
77 {
79 }
80 
82 {
84 }
85 
88 /* -------------------------------------------------------------------- */
99 {
100  return IMB_allocImBuf(
102 }
103 
104 typedef struct PaintTile {
105  struct PaintTile *next, *prev;
108  /* For 2D image painting the ImageUser uses most of the values.
109  * Even though views and passes are stored they are currently not supported for painting.
110  * For 3D projection painting this only uses a tile & frame number.
111  * The scene pointer must be cleared (or temporarily set it as needed, but leave cleared). */
113  union {
114  float *fp;
116  void *pt;
117  } rect;
119  bool valid;
120  bool use_float;
123 
124 static void ptile_free(PaintTile *ptile)
125 {
126  if (ptile->rect.pt) {
127  MEM_freeN(ptile->rect.pt);
128  }
129  if (ptile->mask) {
130  MEM_freeN(ptile->mask);
131  }
132  MEM_freeN(ptile);
133 }
134 
135 static void ptile_free_list(ListBase *paint_tiles)
136 {
137  for (PaintTile *ptile = paint_tiles->first, *ptile_next; ptile; ptile = ptile_next) {
138  ptile_next = ptile->next;
139  ptile_free(ptile);
140  }
141  BLI_listbase_clear(paint_tiles);
142 }
143 
144 static void ptile_invalidate_list(ListBase *paint_tiles)
145 {
146  LISTBASE_FOREACH (PaintTile *, ptile, paint_tiles) {
147  ptile->valid = false;
148  }
149 }
150 
152  Image *image,
153  ImBuf *ibuf,
154  ImageUser *iuser,
155  int x_tile,
156  int y_tile,
157  ushort **r_mask,
158  bool validate)
159 {
160  LISTBASE_FOREACH (PaintTile *, ptile, paint_tiles) {
161  if (ptile->x_tile == x_tile && ptile->y_tile == y_tile) {
162  if (ptile->image == image && ptile->ibuf == ibuf && ptile->iuser.tile == iuser->tile) {
163  if (r_mask) {
164  /* allocate mask if requested. */
165  if (!ptile->mask) {
166  ptile->mask = MEM_callocN(sizeof(ushort) * square_i(ED_IMAGE_UNDO_TILE_SIZE),
167  "UndoImageTile.mask");
168  }
169  *r_mask = ptile->mask;
170  }
171  if (validate) {
172  ptile->valid = true;
173  }
174  return ptile->rect.pt;
175  }
176  }
177  }
178  return NULL;
179 }
180 
182  Image *image,
183  ImBuf *ibuf,
184  ImBuf **tmpibuf,
185  ImageUser *iuser,
186  int x_tile,
187  int y_tile,
188  ushort **r_mask,
189  bool **r_valid,
190  bool use_thread_lock,
191  bool find_prev)
192 {
193  const bool has_float = (ibuf->rect_float != NULL);
194 
195  /* check if tile is already pushed */
196 
197  /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */
198  if (find_prev) {
200  paint_tiles, image, ibuf, iuser, x_tile, y_tile, r_mask, true);
201  if (data) {
202  return data;
203  }
204  }
205 
206  if (*tmpibuf == NULL) {
207  *tmpibuf = imbuf_alloc_temp_tile();
208  }
209 
210  PaintTile *ptile = MEM_callocN(sizeof(PaintTile), "PaintTile");
211 
212  ptile->image = image;
213  ptile->ibuf = ibuf;
214  ptile->iuser = *iuser;
215  ptile->iuser.scene = NULL;
216 
217  ptile->x_tile = x_tile;
218  ptile->y_tile = y_tile;
219 
220  /* add mask explicitly here */
221  if (r_mask) {
222  *r_mask = ptile->mask = MEM_callocN(sizeof(ushort) * square_i(ED_IMAGE_UNDO_TILE_SIZE),
223  "PaintTile.mask");
224  }
225 
226  ptile->rect.pt = MEM_callocN((ibuf->rect_float ? sizeof(float[4]) : sizeof(char[4])) *
228  "PaintTile.rect");
229 
230  ptile->use_float = has_float;
231  ptile->valid = true;
232 
233  if (r_valid) {
234  *r_valid = &ptile->valid;
235  }
236 
237  IMB_rectcpy(*tmpibuf,
238  ibuf,
239  0,
240  0,
241  x_tile * ED_IMAGE_UNDO_TILE_SIZE,
242  y_tile * ED_IMAGE_UNDO_TILE_SIZE,
245 
246  if (has_float) {
247  SWAP(float *, ptile->rect.fp, (*tmpibuf)->rect_float);
248  }
249  else {
250  SWAP(uint *, ptile->rect.uint, (*tmpibuf)->rect);
251  }
252 
253  if (use_thread_lock) {
255  }
256  BLI_addtail(paint_tiles, ptile);
257 
258  if (use_thread_lock) {
260  }
261  return ptile->rect.pt;
262 }
263 
264 static void ptile_restore_runtime_list(ListBase *paint_tiles)
265 {
266  ImBuf *tmpibuf = imbuf_alloc_temp_tile();
267 
268  LISTBASE_FOREACH (PaintTile *, ptile, paint_tiles) {
269  Image *image = ptile->image;
270  ImBuf *ibuf = BKE_image_acquire_ibuf(image, &ptile->iuser, NULL);
271  const bool has_float = (ibuf->rect_float != NULL);
272 
273  if (has_float) {
274  SWAP(float *, ptile->rect.fp, tmpibuf->rect_float);
275  }
276  else {
277  SWAP(uint *, ptile->rect.uint, tmpibuf->rect);
278  }
279 
280  IMB_rectcpy(ibuf,
281  tmpibuf,
282  ptile->x_tile * ED_IMAGE_UNDO_TILE_SIZE,
283  ptile->y_tile * ED_IMAGE_UNDO_TILE_SIZE,
284  0,
285  0,
288 
289  if (has_float) {
290  SWAP(float *, ptile->rect.fp, tmpibuf->rect_float);
291  }
292  else {
293  SWAP(uint *, ptile->rect.uint, tmpibuf->rect);
294  }
295 
297  image); /* force OpenGL reload (maybe partial update will operate better?) */
298  if (ibuf->rect_float) {
299  ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
300  }
301  if (ibuf->mipmap[0]) {
302  ibuf->userflags |= IB_MIPMAP_INVALID; /* force mip-map recreation. */
303  }
305 
306  BKE_image_release_ibuf(image, ibuf, NULL);
307  }
308 
309  IMB_freeImBuf(tmpibuf);
310 }
311 
314 /* -------------------------------------------------------------------- */
318 static uint index_from_xy(uint tile_x, uint tile_y, const uint tiles_dims[2])
319 {
320  BLI_assert(tile_x < tiles_dims[0] && tile_y < tiles_dims[1]);
321  return (tile_y * tiles_dims[0]) + tile_x;
322 }
323 
324 typedef struct UndoImageTile {
325  union {
326  float *fp;
328  void *pt;
329  } rect;
330  int users;
332 
333 static UndoImageTile *utile_alloc(bool has_float)
334 {
335  UndoImageTile *utile = MEM_callocN(sizeof(*utile), "ImageUndoTile");
336  if (has_float) {
337  utile->rect.fp = MEM_mallocN(sizeof(float[4]) * square_i(ED_IMAGE_UNDO_TILE_SIZE), __func__);
338  }
339  else {
340  utile->rect.uint = MEM_mallocN(sizeof(uint) * square_i(ED_IMAGE_UNDO_TILE_SIZE), __func__);
341  }
342  return utile;
343 }
344 
346  UndoImageTile *utile, const uint x, const uint y, const ImBuf *ibuf, ImBuf *tmpibuf)
347 {
348  const bool has_float = ibuf->rect_float;
349 
350  if (has_float) {
351  SWAP(float *, utile->rect.fp, tmpibuf->rect_float);
352  }
353  else {
354  SWAP(uint *, utile->rect.uint, tmpibuf->rect);
355  }
356 
358 
359  if (has_float) {
360  SWAP(float *, utile->rect.fp, tmpibuf->rect_float);
361  }
362  else {
363  SWAP(uint *, utile->rect.uint, tmpibuf->rect);
364  }
365 }
366 
367 static void utile_restore(
368  const UndoImageTile *utile, const uint x, const uint y, ImBuf *ibuf, ImBuf *tmpibuf)
369 {
370  const bool has_float = ibuf->rect_float;
371  float *prev_rect_float = tmpibuf->rect_float;
372  uint *prev_rect = tmpibuf->rect;
373 
374  if (has_float) {
375  tmpibuf->rect_float = utile->rect.fp;
376  }
377  else {
378  tmpibuf->rect = utile->rect.uint;
379  }
380 
382 
383  tmpibuf->rect_float = prev_rect_float;
384  tmpibuf->rect = prev_rect;
385 }
386 
387 static void utile_decref(UndoImageTile *utile)
388 {
389  utile->users -= 1;
390  BLI_assert(utile->users >= 0);
391  if (utile->users == 0) {
392  MEM_freeN(utile->rect.pt);
393  MEM_freeN(utile);
394  }
395 }
396 
399 /* -------------------------------------------------------------------- */
403 typedef struct UndoImageBuf {
404  struct UndoImageBuf *next, *prev;
405 
410 
412 
414 
418 
420 
422  struct {
423  short source;
424  bool use_float;
425  char gen_type;
427 
429 
430 static UndoImageBuf *ubuf_from_image_no_tiles(Image *image, const ImBuf *ibuf)
431 {
432  UndoImageBuf *ubuf = MEM_callocN(sizeof(*ubuf), __func__);
433 
434  ubuf->image_dims[0] = ibuf->x;
435  ubuf->image_dims[1] = ibuf->y;
436 
437  ubuf->tiles_dims[0] = ED_IMAGE_UNDO_TILE_NUMBER(ubuf->image_dims[0]);
438  ubuf->tiles_dims[1] = ED_IMAGE_UNDO_TILE_NUMBER(ubuf->image_dims[1]);
439 
440  ubuf->tiles_len = ubuf->tiles_dims[0] * ubuf->tiles_dims[1];
441  ubuf->tiles = MEM_callocN(sizeof(*ubuf->tiles) * ubuf->tiles_len, __func__);
442 
443  BLI_strncpy(ubuf->ibuf_name, ibuf->name, sizeof(ubuf->ibuf_name));
444  ubuf->image_state.gen_type = image->gen_type;
445  ubuf->image_state.source = image->source;
446  ubuf->image_state.use_float = ibuf->rect_float != NULL;
447 
448  return ubuf;
449 }
450 
451 static void ubuf_from_image_all_tiles(UndoImageBuf *ubuf, const ImBuf *ibuf)
452 {
453  ImBuf *tmpibuf = imbuf_alloc_temp_tile();
454 
455  const bool has_float = ibuf->rect_float;
456  int i = 0;
457  for (uint y_tile = 0; y_tile < ubuf->tiles_dims[1]; y_tile += 1) {
458  uint y = y_tile << ED_IMAGE_UNDO_TILE_BITS;
459  for (uint x_tile = 0; x_tile < ubuf->tiles_dims[0]; x_tile += 1) {
460  uint x = x_tile << ED_IMAGE_UNDO_TILE_BITS;
461 
462  BLI_assert(ubuf->tiles[i] == NULL);
463  UndoImageTile *utile = utile_alloc(has_float);
464  utile->users = 1;
465  utile_init_from_imbuf(utile, x, y, ibuf, tmpibuf);
466  ubuf->tiles[i] = utile;
467 
468  i += 1;
469  }
470  }
471 
472  BLI_assert(i == ubuf->tiles_len);
473 
474  IMB_freeImBuf(tmpibuf);
475 }
476 
478 static void ubuf_ensure_compat_ibuf(const UndoImageBuf *ubuf, ImBuf *ibuf)
479 {
480  /* We could have both float and rect buffers,
481  * in this case free the float buffer if it's unused. */
482  if ((ibuf->rect_float != NULL) && (ubuf->image_state.use_float == false)) {
484  }
485 
486  if (ibuf->x == ubuf->image_dims[0] && ibuf->y == ubuf->image_dims[1] &&
487  (ubuf->image_state.use_float ? (void *)ibuf->rect_float : (void *)ibuf->rect)) {
488  return;
489  }
490 
491  imb_freerectImbuf_all(ibuf);
492  IMB_rect_size_set(ibuf, ubuf->image_dims);
493 
494  if (ubuf->image_state.use_float) {
495  imb_addrectfloatImBuf(ibuf);
496  }
497  else {
498  imb_addrectImBuf(ibuf);
499  }
500 }
501 
502 static void ubuf_free(UndoImageBuf *ubuf)
503 {
504  UndoImageBuf *ubuf_post = ubuf->post;
505  for (uint i = 0; i < ubuf->tiles_len; i++) {
506  UndoImageTile *utile = ubuf->tiles[i];
507  utile_decref(utile);
508  }
509  MEM_freeN(ubuf->tiles);
510  MEM_freeN(ubuf);
511  if (ubuf_post) {
512  ubuf_free(ubuf_post);
513  }
514 }
515 
518 /* -------------------------------------------------------------------- */
522 typedef struct UndoImageHandle {
524 
526  UndoRefID_Image image_ref;
527 
532 
537 
539 
540 static void uhandle_restore_list(ListBase *undo_handles, bool use_init)
541 {
542  ImBuf *tmpibuf = imbuf_alloc_temp_tile();
543 
544  LISTBASE_FOREACH (UndoImageHandle *, uh, undo_handles) {
545  /* Tiles only added to second set of tiles. */
546  Image *image = uh->image_ref.ptr;
547 
548  ImBuf *ibuf = BKE_image_acquire_ibuf(image, &uh->iuser, NULL);
549  if (UNLIKELY(ibuf == NULL)) {
550  CLOG_ERROR(&LOG, "Unable to get buffer for image '%s'", image->id.name + 2);
551  continue;
552  }
553  bool changed = false;
554  LISTBASE_FOREACH (UndoImageBuf *, ubuf_iter, &uh->buffers) {
555  UndoImageBuf *ubuf = use_init ? ubuf_iter : ubuf_iter->post;
556  ubuf_ensure_compat_ibuf(ubuf, ibuf);
557 
558  int i = 0;
559  for (uint y_tile = 0; y_tile < ubuf->tiles_dims[1]; y_tile += 1) {
560  uint y = y_tile << ED_IMAGE_UNDO_TILE_BITS;
561  for (uint x_tile = 0; x_tile < ubuf->tiles_dims[0]; x_tile += 1) {
562  uint x = x_tile << ED_IMAGE_UNDO_TILE_BITS;
563  utile_restore(ubuf->tiles[i], x, y, ibuf, tmpibuf);
564  changed = true;
565  i += 1;
566  }
567  }
568  }
569 
570  if (changed) {
571  BKE_image_mark_dirty(image, ibuf);
572  BKE_image_free_gputextures(image); /* force OpenGL reload */
573 
574  if (ibuf->rect_float) {
575  ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
576  }
577  if (ibuf->mipmap[0]) {
578  ibuf->userflags |= IB_MIPMAP_INVALID; /* force mip-map recreation. */
579  }
581 
582  DEG_id_tag_update(&image->id, 0);
583  }
584  BKE_image_release_ibuf(image, ibuf, NULL);
585  }
586 
587  IMB_freeImBuf(tmpibuf);
588 }
589 
590 static void uhandle_free_list(ListBase *undo_handles)
591 {
592  LISTBASE_FOREACH_MUTABLE (UndoImageHandle *, uh, undo_handles) {
593  LISTBASE_FOREACH_MUTABLE (UndoImageBuf *, ubuf, &uh->buffers) {
594  ubuf_free(ubuf);
595  }
596  MEM_freeN(uh);
597  }
598  BLI_listbase_clear(undo_handles);
599 }
600 
603 /* -------------------------------------------------------------------- */
610  const Image *UNUSED(image),
611  const char *ibuf_name)
612 {
613  LISTBASE_FOREACH (UndoImageBuf *, ubuf, &uh->buffers) {
614  if (STREQ(ubuf->ibuf_name, ibuf_name)) {
615  return ubuf;
616  }
617  }
618  return NULL;
619 }
620 
622 {
623  BLI_assert(uhandle_lookup_ubuf(uh, image, ibuf->name) == NULL);
624  UndoImageBuf *ubuf = ubuf_from_image_no_tiles(image, ibuf);
625  BLI_addtail(&uh->buffers, ubuf);
626 
627  ubuf->post = NULL;
628 
629  return ubuf;
630 }
631 
633 {
634  UndoImageBuf *ubuf = uhandle_lookup_ubuf(uh, image, ibuf->name);
635  if (ubuf == NULL) {
636  ubuf = uhandle_add_ubuf(uh, image, ibuf);
637  }
638  return ubuf;
639 }
640 
642  const Image *image,
643  int tile_number)
644 {
645  LISTBASE_FOREACH (UndoImageHandle *, uh, undo_handles) {
646  if (STREQ(image->id.name + 2, uh->image_ref.name + 2) && uh->iuser.tile == tile_number) {
647  return uh;
648  }
649  }
650  return NULL;
651 }
652 
653 static UndoImageHandle *uhandle_lookup(ListBase *undo_handles, const Image *image, int tile_number)
654 {
655  LISTBASE_FOREACH (UndoImageHandle *, uh, undo_handles) {
656  if (image == uh->image_ref.ptr && uh->iuser.tile == tile_number) {
657  return uh;
658  }
659  }
660  return NULL;
661 }
662 
663 static UndoImageHandle *uhandle_add(ListBase *undo_handles, Image *image, ImageUser *iuser)
664 {
665  BLI_assert(uhandle_lookup(undo_handles, image, iuser->tile) == NULL);
666  UndoImageHandle *uh = MEM_callocN(sizeof(*uh), __func__);
667  uh->image_ref.ptr = image;
668  uh->iuser = *iuser;
669  uh->iuser.scene = NULL;
670  uh->iuser.ok = 1;
671  BLI_addtail(undo_handles, uh);
672  return uh;
673 }
674 
675 static UndoImageHandle *uhandle_ensure(ListBase *undo_handles, Image *image, ImageUser *iuser)
676 {
677  UndoImageHandle *uh = uhandle_lookup(undo_handles, image, iuser->tile);
678  if (uh == NULL) {
679  uh = uhandle_add(undo_handles, image, iuser);
680  }
681  return uh;
682 }
683 
686 /* -------------------------------------------------------------------- */
690 typedef struct ImageUndoStep {
692 
695 
701 
704 
706 
712  const Image *image,
713  int tile_number,
714  const UndoImageBuf *ubuf)
715 {
716  /* Use name lookup because the pointer is cleared for previous steps. */
717  UndoImageHandle *uh_prev = uhandle_lookup_by_name(&us_prev->handles, image, tile_number);
718  if (uh_prev != NULL) {
719  UndoImageBuf *ubuf_reference = uhandle_lookup_ubuf(uh_prev, image, ubuf->ibuf_name);
720  if (ubuf_reference) {
721  ubuf_reference = ubuf_reference->post;
722  if ((ubuf_reference->image_dims[0] == ubuf->image_dims[0]) &&
723  (ubuf_reference->image_dims[1] == ubuf->image_dims[1])) {
724  return ubuf_reference;
725  }
726  }
727  }
728  return NULL;
729 }
730 
732 {
733  Object *obact = CTX_data_active_object(C);
734 
736  if (area && (area->spacetype == SPACE_IMAGE)) {
737  SpaceImage *sima = (SpaceImage *)area->spacedata.first;
738  if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) {
739  return true;
740  }
741  }
742  else {
743  if (obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) {
744  return true;
745  }
746  }
747  return false;
748 }
749 
751 {
752  ImageUndoStep *us = (ImageUndoStep *)us_p;
753  /* dummy, memory is cleared anyway. */
754  us->is_encode_init = true;
757 }
758 
760  struct Main *UNUSED(bmain),
761  UndoStep *us_p)
762 {
763  /* Encoding is done along the way by adding tiles
764  * to the current 'ImageUndoStep' added by encode_init.
765  *
766  * This function ensures there are previous and current states of the image in the undo buffer.
767  */
768  ImageUndoStep *us = (ImageUndoStep *)us_p;
769 
770  BLI_assert(us->step.data_size == 0);
771 
772  if (us->is_encode_init) {
773 
774  ImBuf *tmpibuf = imbuf_alloc_temp_tile();
775 
777  while (us_reference && us_reference->step.type != BKE_UNDOSYS_TYPE_IMAGE) {
778  us_reference = (ImageUndoStep *)us_reference->step.prev;
779  }
780 
781  /* Initialize undo tiles from ptiles (if they exist). */
782  for (PaintTile *ptile = us->paint_tiles.first, *ptile_next; ptile; ptile = ptile_next) {
783  if (ptile->valid) {
784  UndoImageHandle *uh = uhandle_ensure(&us->handles, ptile->image, &ptile->iuser);
785  UndoImageBuf *ubuf_pre = uhandle_ensure_ubuf(uh, ptile->image, ptile->ibuf);
786 
787  UndoImageTile *utile = MEM_callocN(sizeof(*utile), "UndoImageTile");
788  utile->users = 1;
789  utile->rect.pt = ptile->rect.pt;
790  ptile->rect.pt = NULL;
791  const uint tile_index = index_from_xy(ptile->x_tile, ptile->y_tile, ubuf_pre->tiles_dims);
792 
793  BLI_assert(ubuf_pre->tiles[tile_index] == NULL);
794  ubuf_pre->tiles[tile_index] = utile;
795  }
796  ptile_next = ptile->next;
797  ptile_free(ptile);
798  }
800 
802  LISTBASE_FOREACH (UndoImageBuf *, ubuf_pre, &uh->buffers) {
803 
804  ImBuf *ibuf = BKE_image_acquire_ibuf(uh->image_ref.ptr, &uh->iuser, NULL);
805 
806  const bool has_float = ibuf->rect_float;
807 
808  BLI_assert(ubuf_pre->post == NULL);
809  ubuf_pre->post = ubuf_from_image_no_tiles(uh->image_ref.ptr, ibuf);
810  UndoImageBuf *ubuf_post = ubuf_pre->post;
811 
812  if (ubuf_pre->image_dims[0] != ubuf_post->image_dims[0] ||
813  ubuf_pre->image_dims[1] != ubuf_post->image_dims[1]) {
814  ubuf_from_image_all_tiles(ubuf_post, ibuf);
815  }
816  else {
817  /* Search for the previous buffer. */
818  UndoImageBuf *ubuf_reference =
819  (us_reference ? ubuf_lookup_from_reference(
820  us_reference, uh->image_ref.ptr, uh->iuser.tile, ubuf_post) :
821  NULL);
822 
823  int i = 0;
824  for (uint y_tile = 0; y_tile < ubuf_pre->tiles_dims[1]; y_tile += 1) {
825  uint y = y_tile << ED_IMAGE_UNDO_TILE_BITS;
826  for (uint x_tile = 0; x_tile < ubuf_pre->tiles_dims[0]; x_tile += 1) {
827  uint x = x_tile << ED_IMAGE_UNDO_TILE_BITS;
828 
829  if ((ubuf_reference != NULL) && ((ubuf_pre->tiles[i] == NULL) ||
830  /* In this case the paint stroke as has added a tile
831  * which we have a duplicate reference available. */
832  (ubuf_pre->tiles[i]->users == 1))) {
833  if (ubuf_pre->tiles[i] != NULL) {
834  /* If we have a reference, re-use this single use tile for the post state. */
835  BLI_assert(ubuf_pre->tiles[i]->users == 1);
836  ubuf_post->tiles[i] = ubuf_pre->tiles[i];
837  ubuf_pre->tiles[i] = NULL;
838  utile_init_from_imbuf(ubuf_post->tiles[i], x, y, ibuf, tmpibuf);
839  }
840  else {
841  BLI_assert(ubuf_post->tiles[i] == NULL);
842  ubuf_post->tiles[i] = ubuf_reference->tiles[i];
843  ubuf_post->tiles[i]->users += 1;
844  }
845  BLI_assert(ubuf_pre->tiles[i] == NULL);
846  ubuf_pre->tiles[i] = ubuf_reference->tiles[i];
847  ubuf_pre->tiles[i]->users += 1;
848 
849  BLI_assert(ubuf_pre->tiles[i] != NULL);
850  BLI_assert(ubuf_post->tiles[i] != NULL);
851  }
852  else {
853  UndoImageTile *utile = utile_alloc(has_float);
854  utile_init_from_imbuf(utile, x, y, ibuf, tmpibuf);
855 
856  if (ubuf_pre->tiles[i] != NULL) {
857  ubuf_post->tiles[i] = utile;
858  utile->users = 1;
859  }
860  else {
861  ubuf_pre->tiles[i] = utile;
862  ubuf_post->tiles[i] = utile;
863  utile->users = 2;
864  }
865  }
866  BLI_assert(ubuf_pre->tiles[i] != NULL);
867  BLI_assert(ubuf_post->tiles[i] != NULL);
868  i += 1;
869  }
870  }
871  BLI_assert(i == ubuf_pre->tiles_len);
872  BLI_assert(i == ubuf_post->tiles_len);
873  }
874  BKE_image_release_ibuf(uh->image_ref.ptr, ibuf, NULL);
875  }
876  }
877 
878  IMB_freeImBuf(tmpibuf);
879 
880  /* Useful to debug tiles are stored correctly. */
881  if (false) {
882  uhandle_restore_list(&us->handles, false);
883  }
884  }
885  else {
886  BLI_assert(C != NULL);
887  /* Happens when switching modes. */
890  us->paint_mode = paint_mode;
891  }
892 
893  us_p->is_applied = true;
894 
895  return true;
896 }
897 
898 static void image_undosys_step_decode_undo_impl(ImageUndoStep *us, bool is_final)
899 {
900  BLI_assert(us->step.is_applied == true);
901  uhandle_restore_list(&us->handles, !is_final);
902  us->step.is_applied = false;
903 }
904 
906 {
907  BLI_assert(us->step.is_applied == false);
908  uhandle_restore_list(&us->handles, false);
909  us->step.is_applied = true;
910 }
911 
912 static void image_undosys_step_decode_undo(ImageUndoStep *us, bool is_final)
913 {
914  /* Walk forward over any applied steps of same type,
915  * then walk back in the next loop, un-applying them. */
916  ImageUndoStep *us_iter = us;
917  while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) {
918  if (us_iter->step.next->is_applied == false) {
919  break;
920  }
921  us_iter = (ImageUndoStep *)us_iter->step.next;
922  }
923  while (us_iter != us || (!is_final && us_iter == us)) {
924  BLI_assert(us_iter->step.type == us->step.type); /* Previous loop ensures this. */
925  image_undosys_step_decode_undo_impl(us_iter, is_final);
926  if (us_iter == us) {
927  break;
928  }
929  us_iter = (ImageUndoStep *)us_iter->step.prev;
930  }
931 }
932 
934 {
935  ImageUndoStep *us_iter = us;
936  while (us_iter->step.prev && (us_iter->step.prev->type == us_iter->step.type)) {
937  if (us_iter->step.prev->is_applied == true) {
938  break;
939  }
940  us_iter = (ImageUndoStep *)us_iter->step.prev;
941  }
942  while (us_iter && (us_iter->step.is_applied == false)) {
944  if (us_iter == us) {
945  break;
946  }
947  us_iter = (ImageUndoStep *)us_iter->step.next;
948  }
949 }
950 
952  struct bContext *C, struct Main *bmain, UndoStep *us_p, const eUndoStepDir dir, bool is_final)
953 {
954  /* NOTE: behavior for undo/redo closely matches sculpt undo. */
955  BLI_assert(dir != STEP_INVALID);
956 
957  ImageUndoStep *us = (ImageUndoStep *)us_p;
958  if (dir == STEP_UNDO) {
959  image_undosys_step_decode_undo(us, is_final);
960  }
961  else if (dir == STEP_REDO) {
963  }
964 
965  if (us->paint_mode == PAINT_MODE_TEXTURE_3D) {
967  }
968 
969  /* Refresh texture slots. */
971 }
972 
974 {
975  ImageUndoStep *us = (ImageUndoStep *)us_p;
977 
978  /* Typically this list will have been cleared. */
980 }
981 
983  UndoTypeForEachIDRefFn foreach_ID_ref_fn,
984  void *user_data)
985 {
986  ImageUndoStep *us = (ImageUndoStep *)us_p;
988  foreach_ID_ref_fn(user_data, ((UndoRefID *)&uh->image_ref));
989  }
990 }
991 
992 /* Export for ED_undo_sys. */
994 {
995  ut->name = "Image";
996  ut->poll = image_undosys_poll;
1001 
1003 
1004  /* NOTE this is actually a confusing case, since it expects a valid context, but only in a
1005  * specific case, see `image_undosys_step_encode` code. We cannot specify
1006  * `UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE` though, as it can be called with a NULL context by
1007  * current code. */
1008  ut->flags = 0;
1009 
1010  ut->step_size = sizeof(ImageUndoStep);
1011 }
1012 
1015 /* -------------------------------------------------------------------- */
1028 {
1029  UndoStack *ustack = ED_undo_stack_get();
1030  UndoStep *us_prev = ustack->step_init;
1032  ImageUndoStep *us = (ImageUndoStep *)us_p;
1033  /* We should always have an undo push started when accessing tiles,
1034  * not doing this means we won't have paint_mode correctly set. */
1035  BLI_assert(us_p == us_prev);
1036  if (us_p != us_prev) {
1037  /* Fallback value until we can be sure this never happens. */
1039  }
1040  return &us->paint_tiles;
1041 }
1042 
1043 /* restore painting image to previous state. Used for anchored and drag-dot style brushes*/
1045 {
1046  ListBase *paint_tiles = &((ImageUndoStep *)us)->paint_tiles;
1047  ptile_restore_runtime_list(paint_tiles);
1048  ptile_invalidate_list(paint_tiles);
1049 }
1050 
1051 static ImageUndoStep *image_undo_push_begin(const char *name, int paint_mode)
1052 {
1053  UndoStack *ustack = ED_undo_stack_get();
1054  bContext *C = NULL; /* special case, we never read from this. */
1056  ImageUndoStep *us = (ImageUndoStep *)us_p;
1058  us->paint_mode = paint_mode;
1059  return us;
1060 }
1061 
1066 void ED_image_undo_push_begin(const char *name, int paint_mode)
1067 {
1068  image_undo_push_begin(name, paint_mode);
1069 }
1070 
1072  Image *image,
1073  ImBuf *ibuf,
1074  ImageUser *iuser)
1075 {
1077 
1078  BLI_assert(BKE_image_get_tile(image, iuser->tile));
1079  UndoImageHandle *uh = uhandle_ensure(&us->handles, image, iuser);
1080  UndoImageBuf *ubuf_pre = uhandle_ensure_ubuf(uh, image, ibuf);
1081  BLI_assert(ubuf_pre->post == NULL);
1082 
1084  while (us_reference && us_reference->step.type != BKE_UNDOSYS_TYPE_IMAGE) {
1085  us_reference = (ImageUndoStep *)us_reference->step.prev;
1086  }
1087  UndoImageBuf *ubuf_reference = (us_reference ? ubuf_lookup_from_reference(
1088  us_reference, image, iuser->tile, ubuf_pre) :
1089  NULL);
1090 
1091  if (ubuf_reference) {
1092  memcpy(ubuf_pre->tiles, ubuf_reference->tiles, sizeof(*ubuf_pre->tiles) * ubuf_pre->tiles_len);
1093  for (uint i = 0; i < ubuf_pre->tiles_len; i++) {
1094  UndoImageTile *utile = ubuf_pre->tiles[i];
1095  utile->users += 1;
1096  }
1097  }
1098  else {
1099  ubuf_from_image_all_tiles(ubuf_pre, ibuf);
1100  }
1101 }
1102 
1104 {
1105  UndoStack *ustack = ED_undo_stack_get();
1106  BKE_undosys_step_push(ustack, NULL, NULL);
1109 }
1110 
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:714
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1279
void BKE_image_release_ibuf(struct Image *ima, struct ImBuf *ibuf, void *lock)
Definition: image.c:5113
struct ImBuf * BKE_image_acquire_ibuf(struct Image *ima, struct ImageUser *iuser, void **r_lock)
Definition: image.c:5100
void BKE_image_free_gputextures(struct Image *ima)
Definition: image_gpu.c:517
void BKE_image_mark_dirty(struct Image *image, struct ImBuf *ibuf)
ePaintMode BKE_paintmode_get_active_from_context(const struct bContext *C)
ePaintMode
Definition: BKE_paint.h:78
@ PAINT_MODE_TEXTURE_3D
Definition: BKE_paint.h:84
@ PAINT_MODE_TEXTURE_2D
Definition: BKE_paint.h:86
UndoStep * BKE_undosys_step_push_init_with_type(UndoStack *ustack, struct bContext *C, const char *name, const UndoType *ut)
Definition: undo_system.c:458
UndoStep * BKE_undosys_stack_init_or_active_with_type(UndoStack *ustack, const UndoType *ut)
Definition: undo_system.c:390
eUndoStepDir
@ STEP_INVALID
@ STEP_UNDO
@ STEP_REDO
#define BKE_undosys_stack_limit_steps_and_memory_defaults(ustack)
UndoPushReturn BKE_undosys_step_push(UndoStack *ustack, struct bContext *C, const char *name)
Definition: undo_system.c:605
const UndoType * BKE_UNDOSYS_TYPE_IMAGE
Definition: undo_system.c:100
void(* UndoTypeForEachIDRefFn)(void *user_data, struct UndoRefID *id_ref)
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:188
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:128
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
MINLINE int square_i(int a)
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
unsigned int uint
Definition: BLI_sys_types.h:83
unsigned short ushort
Definition: BLI_sys_types.h:84
pthread_spinlock_t SpinLock
Definition: BLI_threads.h:111
void BLI_spin_init(SpinLock *spin)
Definition: threads.cc:447
void BLI_spin_unlock(SpinLock *spin)
Definition: threads.cc:480
void BLI_spin_lock(SpinLock *spin)
Definition: threads.cc:461
void BLI_spin_end(SpinLock *spin)
Definition: threads.cc:495
#define SWAP(type, a, b)
#define UNUSED(x)
#define UNLIKELY(x)
#define ELEM(...)
#define STREQ(a, b)
#define CLOG_ERROR(clg_ref,...)
Definition: CLG_log.h:204
void DEG_id_tag_update(struct ID *id, int flag)
@ OB_MODE_TEXTURE_PAINT
Object is a sort of wrapper for general info.
@ SPACE_IMAGE
@ SI_MODE_PAINT
bool ED_object_mode_set_ex(struct bContext *C, eObjectMode mode, bool use_undo, struct ReportList *reports)
Definition: object_modes.c:195
#define ED_IMAGE_UNDO_TILE_NUMBER(size)
Definition: ED_paint.h:99
#define ED_IMAGE_UNDO_TILE_SIZE
Definition: ED_paint.h:98
#define ED_IMAGE_UNDO_TILE_BITS
Definition: ED_paint.h:97
struct UndoStack * ED_undo_stack_get(void)
Definition: ed_undo.c:501
void ED_editors_init_for_undo(struct Main *bmain)
Definition: ed_util.c:68
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
void imb_freerectfloatImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:97
struct ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
Definition: allocimbuf.c:478
void IMB_freeImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:211
void IMB_rect_size_set(struct ImBuf *ibuf, const uint size[2])
Definition: rectop.c:308
void imb_freerectImbuf_all(struct ImBuf *ibuf)
Definition: allocimbuf.c:201
bool imb_addrectfloatImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:386
bool imb_addrectImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:407
void IMB_rectcpy(struct ImBuf *dbuf, const struct ImBuf *sbuf, int destx, int desty, int srcx, int srcy, int width, int height)
Contains defines and structs used throughout the imbuf module.
@ IB_RECT_INVALID
@ IB_MIPMAP_INVALID
@ IB_DISPLAY_BUFFER_INVALID
#define IMB_FILENAME_SIZE
@ IB_rectfloat
@ IB_rect
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:39
char gen_type
short source
void * user_data
static uint index_from_xy(uint tile_x, uint tile_y, const uint tiles_dims[2])
Definition: image_undo.c:318
struct UndoImageTile UndoImageTile
static void utile_decref(UndoImageTile *utile)
Definition: image_undo.c:387
static bool image_undosys_step_encode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p)
Definition: image_undo.c:759
ListBase * ED_image_paint_tile_list_get(void)
Definition: image_undo.c:1027
static void uhandle_restore_list(ListBase *undo_handles, bool use_init)
Definition: image_undo.c:540
static UndoImageTile * utile_alloc(bool has_float)
Definition: image_undo.c:333
static void ptile_free(PaintTile *ptile)
Definition: image_undo.c:124
static ImBuf * imbuf_alloc_temp_tile(void)
Definition: image_undo.c:98
static void image_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p)
Definition: image_undo.c:750
static void ptile_restore_runtime_list(ListBase *paint_tiles)
Definition: image_undo.c:264
void * ED_image_paint_tile_find(ListBase *paint_tiles, Image *image, ImBuf *ibuf, ImageUser *iuser, int x_tile, int y_tile, ushort **r_mask, bool validate)
Definition: image_undo.c:151
static ImageUndoStep * image_undo_push_begin(const char *name, int paint_mode)
Definition: image_undo.c:1051
static void image_undosys_step_decode(struct bContext *C, struct Main *bmain, UndoStep *us_p, const eUndoStepDir dir, bool is_final)
Definition: image_undo.c:951
static UndoImageHandle * uhandle_lookup_by_name(ListBase *undo_handles, const Image *image, int tile_number)
Definition: image_undo.c:641
void ED_image_undo_push_begin_with_image(const char *name, Image *image, ImBuf *ibuf, ImageUser *iuser)
Definition: image_undo.c:1071
static void uhandle_free_list(ListBase *undo_handles)
Definition: image_undo.c:590
void ED_image_undo_push_begin(const char *name, int paint_mode)
Definition: image_undo.c:1066
void ED_image_undosys_type(UndoType *ut)
Definition: image_undo.c:993
static UndoImageBuf * ubuf_from_image_no_tiles(Image *image, const ImBuf *ibuf)
Definition: image_undo.c:430
static void image_undosys_step_decode_undo(ImageUndoStep *us, bool is_final)
Definition: image_undo.c:912
static void ptile_invalidate_list(ListBase *paint_tiles)
Definition: image_undo.c:144
void ED_image_paint_tile_lock_end(void)
Definition: image_undo.c:81
void ED_image_paint_tile_lock_init(void)
Definition: image_undo.c:76
struct PaintTile PaintTile
static void utile_init_from_imbuf(UndoImageTile *utile, const uint x, const uint y, const ImBuf *ibuf, ImBuf *tmpibuf)
Definition: image_undo.c:345
void * ED_image_paint_tile_push(ListBase *paint_tiles, Image *image, ImBuf *ibuf, ImBuf **tmpibuf, ImageUser *iuser, int x_tile, int y_tile, ushort **r_mask, bool **r_valid, bool use_thread_lock, bool find_prev)
Definition: image_undo.c:181
static void image_undosys_foreach_ID_ref(UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
Definition: image_undo.c:982
static UndoImageBuf * uhandle_ensure_ubuf(UndoImageHandle *uh, Image *image, ImBuf *ibuf)
Definition: image_undo.c:632
static UndoImageBuf * uhandle_add_ubuf(UndoImageHandle *uh, Image *image, ImBuf *ibuf)
Definition: image_undo.c:621
static void image_undosys_step_decode_redo(ImageUndoStep *us)
Definition: image_undo.c:933
static UndoImageHandle * uhandle_add(ListBase *undo_handles, Image *image, ImageUser *iuser)
Definition: image_undo.c:663
void ED_image_undo_push_end(void)
Definition: image_undo.c:1103
struct ImageUndoStep ImageUndoStep
static UndoImageHandle * uhandle_ensure(ListBase *undo_handles, Image *image, ImageUser *iuser)
Definition: image_undo.c:675
static void ubuf_ensure_compat_ibuf(const UndoImageBuf *ubuf, ImBuf *ibuf)
Definition: image_undo.c:478
static void image_undosys_step_free(UndoStep *us_p)
Definition: image_undo.c:973
static void image_undosys_step_decode_redo_impl(ImageUndoStep *us)
Definition: image_undo.c:905
static bool image_undosys_poll(bContext *C)
Definition: image_undo.c:731
static void image_undosys_step_decode_undo_impl(ImageUndoStep *us, bool is_final)
Definition: image_undo.c:898
struct UndoImageHandle UndoImageHandle
static CLG_LogRef LOG
Definition: image_undo.c:65
static UndoImageBuf * uhandle_lookup_ubuf(UndoImageHandle *uh, const Image *UNUSED(image), const char *ibuf_name)
Definition: image_undo.c:609
struct UndoImageBuf UndoImageBuf
void ED_image_undo_restore(UndoStep *us)
Definition: image_undo.c:1044
static void ubuf_free(UndoImageBuf *ubuf)
Definition: image_undo.c:502
static void ptile_free_list(ListBase *paint_tiles)
Definition: image_undo.c:135
static UndoImageHandle * uhandle_lookup(ListBase *undo_handles, const Image *image, int tile_number)
Definition: image_undo.c:653
static void ubuf_from_image_all_tiles(UndoImageBuf *ubuf, const ImBuf *ibuf)
Definition: image_undo.c:451
static UndoImageBuf * ubuf_lookup_from_reference(ImageUndoStep *us_prev, const Image *image, int tile_number, const UndoImageBuf *ubuf)
Definition: image_undo.c:711
static SpinLock paint_tiles_lock
Definition: image_undo.c:74
static void utile_restore(const UndoImageTile *utile, const uint x, const uint y, ImBuf *ibuf, ImBuf *tmpibuf)
Definition: image_undo.c:367
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static void area(int d1, int d2, int e1, int e2, float weights[2])
char name[66]
Definition: DNA_ID.h:283
struct ImBuf * mipmap[IMB_MIPMAP_LEVELS]
int userflags
char name[IMB_FILENAME_SIZE]
unsigned int * rect
float * rect_float
ePaintMode paint_mode
Definition: image_undo.c:703
ListBase handles
Definition: image_undo.c:694
UndoStep step
Definition: image_undo.c:691
bool is_encode_init
Definition: image_undo.c:702
ListBase paint_tiles
Definition: image_undo.c:700
struct Scene * scene
void * first
Definition: DNA_listBase.h:47
Definition: BKE_main.h:116
struct PaintTile * next
Definition: image_undo.c:105
Image * image
Definition: image_undo.c:106
bool use_float
Definition: image_undo.c:120
struct PaintTile * prev
Definition: image_undo.c:105
void * pt
Definition: image_undo.c:116
uint * uint
Definition: image_undo.c:115
union PaintTile::@506 rect
ushort * mask
Definition: image_undo.c:118
ImageUser iuser
Definition: image_undo.c:112
bool valid
Definition: image_undo.c:119
float * fp
Definition: image_undo.c:114
ImBuf * ibuf
Definition: image_undo.c:107
int y_tile
Definition: image_undo.c:121
int x_tile
Definition: image_undo.c:121
uint tiles_dims[2]
Definition: image_undo.c:417
struct UndoImageBuf::@508 image_state
UndoImageTile ** tiles
Definition: image_undo.c:413
short source
Definition: image_undo.c:423
uint image_dims[2]
Definition: image_undo.c:419
struct UndoImageBuf * prev
Definition: image_undo.c:404
char ibuf_name[IMB_FILENAME_SIZE]
Definition: image_undo.c:411
bool use_float
Definition: image_undo.c:424
struct UndoImageBuf * post
Definition: image_undo.c:409
struct UndoImageBuf * next
Definition: image_undo.c:404
uint tiles_len
Definition: image_undo.c:416
ImageUser iuser
Definition: image_undo.c:531
UndoRefID_Image image_ref
Definition: image_undo.c:526
ListBase buffers
Definition: image_undo.c:536
struct UndoImageHandle * next
Definition: image_undo.c:523
struct UndoImageHandle * prev
Definition: image_undo.c:523
float * fp
Definition: image_undo.c:326
union UndoImageTile::@507 rect
struct UndoStep * step_active
struct UndoStep * step_init
const struct UndoType * type
bool is_applied
size_t data_size
struct UndoStep * prev
struct UndoStep * next
size_t step_size
void(* step_decode)(struct bContext *C, struct Main *bmain, UndoStep *us, const eUndoStepDir dir, bool is_final)
bool(* step_encode)(struct bContext *C, struct Main *bmain, UndoStep *us)
void(* step_encode_init)(struct bContext *C, UndoStep *us)
void(* step_foreach_ID_ref)(UndoStep *us, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
const char * name
void(* step_free)(UndoStep *us)
bool(* poll)(struct bContext *C)
void WM_file_tag_modified(void)
Definition: wm_files.c:158