Blender  V3.3
image_undo.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
20 #include "CLG_log.h"
21 
22 #include "MEM_guardedalloc.h"
23 
24 #include "BLI_blenlib.h"
25 #include "BLI_map.hh"
26 #include "BLI_math.h"
27 #include "BLI_threads.h"
28 #include "BLI_utildefines.h"
29 
30 #include "DNA_image_types.h"
31 #include "DNA_object_types.h"
32 #include "DNA_screen_types.h"
33 #include "DNA_space_types.h"
35 
36 #include "IMB_imbuf.h"
37 #include "IMB_imbuf_types.h"
38 
39 #include "BKE_context.h"
40 #include "BKE_image.h"
41 #include "BKE_paint.h"
42 #include "BKE_undo_system.h"
43 
44 #include "DEG_depsgraph.h"
45 
46 #include "ED_object.h"
47 #include "ED_paint.h"
48 #include "ED_undo.h"
49 #include "ED_util.h"
50 
51 #include "WM_api.h"
52 
53 static CLG_LogRef LOG = {"ed.image.undo"};
54 
55 /* -------------------------------------------------------------------- */
59 /* This is a non-global static resource,
60  * Maybe it should be exposed as part of the
61  * paint operation, but for now just give a public interface */
63 
65 {
67 }
68 
70 {
72 }
73 
76 /* -------------------------------------------------------------------- */
87 {
88  return IMB_allocImBuf(
90 }
91 
92 struct PaintTileKey {
93  int x_tile, y_tile;
96  /* Copied from iuser.tile in PaintTile. */
98 
99  uint64_t hash() const
100  {
102  }
103  bool operator==(const PaintTileKey &other) const
104  {
105  return x_tile == other.x_tile && y_tile == other.y_tile && image == other.image &&
106  ibuf == other.ibuf && iuser_tile == other.iuser_tile;
107  }
108 };
109 
110 struct PaintTile {
113  /* For 2D image painting the ImageUser uses most of the values.
114  * Even though views and passes are stored they are currently not supported for painting.
115  * For 3D projection painting this only uses a tile & frame number.
116  * The scene pointer must be cleared (or temporarily set it as needed, but leave cleared). */
118  union {
119  float *fp;
121  void *pt;
122  } rect;
124  bool valid;
125  bool use_float;
127 };
128 
129 static void ptile_free(PaintTile *ptile)
130 {
131  if (ptile->rect.pt) {
132  MEM_freeN(ptile->rect.pt);
133  }
134  if (ptile->mask) {
135  MEM_freeN(ptile->mask);
136  }
137  MEM_freeN(ptile);
138 }
139 
140 struct PaintTileMap {
142 
144  {
145  for (PaintTile *ptile : map.values()) {
146  ptile_free(ptile);
147  }
148  }
149 };
150 
151 static void ptile_invalidate_map(PaintTileMap *paint_tile_map)
152 {
153  for (PaintTile *ptile : paint_tile_map->map.values()) {
154  ptile->valid = false;
155  }
156 }
157 
159  Image *image,
160  ImBuf *ibuf,
161  ImageUser *iuser,
162  int x_tile,
163  int y_tile,
164  ushort **r_mask,
165  bool validate)
166 {
167  PaintTileKey key;
168  key.ibuf = ibuf;
169  key.image = image;
170  key.iuser_tile = iuser->tile;
171  key.x_tile = x_tile;
172  key.y_tile = y_tile;
173  PaintTile **pptile = paint_tile_map->map.lookup_ptr(key);
174  if (pptile == nullptr) {
175  return nullptr;
176  }
177  PaintTile *ptile = *pptile;
178  if (r_mask) {
179  /* allocate mask if requested. */
180  if (!ptile->mask) {
181  ptile->mask = static_cast<uint16_t *>(
182  MEM_callocN(sizeof(uint16_t) * square_i(ED_IMAGE_UNDO_TILE_SIZE), "UndoImageTile.mask"));
183  }
184  *r_mask = ptile->mask;
185  }
186  if (validate) {
187  ptile->valid = true;
188  }
189  return ptile->rect.pt;
190 }
191 
193  Image *image,
194  ImBuf *ibuf,
195  ImBuf **tmpibuf,
196  ImageUser *iuser,
197  int x_tile,
198  int y_tile,
199  ushort **r_mask,
200  bool **r_valid,
201  bool use_thread_lock,
202  bool find_prev)
203 {
204  if (use_thread_lock) {
206  }
207  const bool has_float = (ibuf->rect_float != nullptr);
208 
209  /* check if tile is already pushed */
210 
211  /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */
212  if (find_prev) {
214  paint_tile_map, image, ibuf, iuser, x_tile, y_tile, r_mask, true);
215  if (data) {
216  if (use_thread_lock) {
218  }
219  return data;
220  }
221  }
222 
223  if (*tmpibuf == nullptr) {
224  *tmpibuf = imbuf_alloc_temp_tile();
225  }
226 
227  PaintTile *ptile = static_cast<PaintTile *>(MEM_callocN(sizeof(PaintTile), "PaintTile"));
228 
229  ptile->image = image;
230  ptile->ibuf = ibuf;
231  ptile->iuser = *iuser;
232  ptile->iuser.scene = nullptr;
233 
234  ptile->x_tile = x_tile;
235  ptile->y_tile = y_tile;
236 
237  /* add mask explicitly here */
238  if (r_mask) {
239  *r_mask = ptile->mask = static_cast<uint16_t *>(
240  MEM_callocN(sizeof(uint16_t) * square_i(ED_IMAGE_UNDO_TILE_SIZE), "PaintTile.mask"));
241  }
242 
243  ptile->rect.pt = MEM_callocN((ibuf->rect_float ? sizeof(float[4]) : sizeof(char[4])) *
245  "PaintTile.rect");
246 
247  ptile->use_float = has_float;
248  ptile->valid = true;
249 
250  if (r_valid) {
251  *r_valid = &ptile->valid;
252  }
253 
254  IMB_rectcpy(*tmpibuf,
255  ibuf,
256  0,
257  0,
258  x_tile * ED_IMAGE_UNDO_TILE_SIZE,
259  y_tile * ED_IMAGE_UNDO_TILE_SIZE,
262 
263  if (has_float) {
264  SWAP(float *, ptile->rect.fp, (*tmpibuf)->rect_float);
265  }
266  else {
267  SWAP(uint32_t *, ptile->rect.uint, (*tmpibuf)->rect);
268  }
269 
270  PaintTileKey key = {};
271  key.ibuf = ibuf;
272  key.image = image;
273  key.iuser_tile = iuser->tile;
274  key.x_tile = x_tile;
275  key.y_tile = y_tile;
276  PaintTile *existing_tile = nullptr;
277  paint_tile_map->map.add_or_modify(
278  key,
279  [&](PaintTile **pptile) { *pptile = ptile; },
280  [&](PaintTile **pptile) { existing_tile = *pptile; });
281  if (existing_tile) {
282  ptile_free(ptile);
283  ptile = existing_tile;
284  }
285 
286  if (use_thread_lock) {
288  }
289  return ptile->rect.pt;
290 }
291 
292 static void ptile_restore_runtime_map(PaintTileMap *paint_tile_map)
293 {
294  ImBuf *tmpibuf = imbuf_alloc_temp_tile();
295 
296  for (PaintTile *ptile : paint_tile_map->map.values()) {
297  Image *image = ptile->image;
298  ImBuf *ibuf = BKE_image_acquire_ibuf(image, &ptile->iuser, nullptr);
299  const bool has_float = (ibuf->rect_float != nullptr);
300 
301  if (has_float) {
302  SWAP(float *, ptile->rect.fp, tmpibuf->rect_float);
303  }
304  else {
305  SWAP(uint32_t *, ptile->rect.uint, tmpibuf->rect);
306  }
307 
308  IMB_rectcpy(ibuf,
309  tmpibuf,
310  ptile->x_tile * ED_IMAGE_UNDO_TILE_SIZE,
311  ptile->y_tile * ED_IMAGE_UNDO_TILE_SIZE,
312  0,
313  0,
316 
317  if (has_float) {
318  SWAP(float *, ptile->rect.fp, tmpibuf->rect_float);
319  }
320  else {
321  SWAP(uint32_t *, ptile->rect.uint, tmpibuf->rect);
322  }
323 
324  /* Force OpenGL reload (maybe partial update will operate better?) */
326 
327  if (ibuf->rect_float) {
328  ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
329  }
330  if (ibuf->mipmap[0]) {
331  ibuf->userflags |= IB_MIPMAP_INVALID; /* Force MIP-MAP recreation. */
332  }
334 
335  BKE_image_release_ibuf(image, ibuf, nullptr);
336  }
337 
338  IMB_freeImBuf(tmpibuf);
339 }
340 
343 /* -------------------------------------------------------------------- */
347 static uint32_t index_from_xy(uint32_t tile_x, uint32_t tile_y, const uint32_t tiles_dims[2])
348 {
349  BLI_assert(tile_x < tiles_dims[0] && tile_y < tiles_dims[1]);
350  return (tile_y * tiles_dims[0]) + tile_x;
351 }
352 
354  union {
355  float *fp;
357  void *pt;
358  } rect;
359  int users;
360 };
361 
362 static UndoImageTile *utile_alloc(bool has_float)
363 {
364  UndoImageTile *utile = static_cast<UndoImageTile *>(
365  MEM_callocN(sizeof(*utile), "ImageUndoTile"));
366  if (has_float) {
367  utile->rect.fp = static_cast<float *>(
368  MEM_mallocN(sizeof(float[4]) * square_i(ED_IMAGE_UNDO_TILE_SIZE), __func__));
369  }
370  else {
371  utile->rect.uint_ptr = static_cast<uint32_t *>(
372  MEM_mallocN(sizeof(uint32_t) * square_i(ED_IMAGE_UNDO_TILE_SIZE), __func__));
373  }
374  return utile;
375 }
376 
378  UndoImageTile *utile, const uint32_t x, const uint32_t y, const ImBuf *ibuf, ImBuf *tmpibuf)
379 {
380  const bool has_float = ibuf->rect_float;
381 
382  if (has_float) {
383  SWAP(float *, utile->rect.fp, tmpibuf->rect_float);
384  }
385  else {
386  SWAP(uint32_t *, utile->rect.uint_ptr, tmpibuf->rect);
387  }
388 
390 
391  if (has_float) {
392  SWAP(float *, utile->rect.fp, tmpibuf->rect_float);
393  }
394  else {
395  SWAP(uint32_t *, utile->rect.uint_ptr, tmpibuf->rect);
396  }
397 }
398 
399 static void utile_restore(
400  const UndoImageTile *utile, const uint x, const uint y, ImBuf *ibuf, ImBuf *tmpibuf)
401 {
402  const bool has_float = ibuf->rect_float;
403  float *prev_rect_float = tmpibuf->rect_float;
404  uint32_t *prev_rect = tmpibuf->rect;
405 
406  if (has_float) {
407  tmpibuf->rect_float = utile->rect.fp;
408  }
409  else {
410  tmpibuf->rect = utile->rect.uint_ptr;
411  }
412 
414 
415  tmpibuf->rect_float = prev_rect_float;
416  tmpibuf->rect = prev_rect;
417 }
418 
419 static void utile_decref(UndoImageTile *utile)
420 {
421  utile->users -= 1;
422  BLI_assert(utile->users >= 0);
423  if (utile->users == 0) {
424  MEM_freeN(utile->rect.pt);
425  MEM_delete(utile);
426  }
427 }
428 
431 /* -------------------------------------------------------------------- */
435 typedef struct UndoImageBuf {
436  struct UndoImageBuf *next, *prev;
437 
442 
444 
446 
450 
452 
454  struct {
455  short source;
456  bool use_float;
457  char gen_type;
459 
461 
463 {
464  UndoImageBuf *ubuf = static_cast<UndoImageBuf *>(MEM_callocN(sizeof(*ubuf), __func__));
465 
466  ubuf->image_dims[0] = ibuf->x;
467  ubuf->image_dims[1] = ibuf->y;
468 
469  ubuf->tiles_dims[0] = ED_IMAGE_UNDO_TILE_NUMBER(ubuf->image_dims[0]);
470  ubuf->tiles_dims[1] = ED_IMAGE_UNDO_TILE_NUMBER(ubuf->image_dims[1]);
471 
472  ubuf->tiles_len = ubuf->tiles_dims[0] * ubuf->tiles_dims[1];
473  ubuf->tiles = static_cast<UndoImageTile **>(
474  MEM_callocN(sizeof(*ubuf->tiles) * ubuf->tiles_len, __func__));
475 
476  BLI_strncpy(ubuf->ibuf_name, ibuf->name, sizeof(ubuf->ibuf_name));
477  ubuf->image_state.gen_type = image->gen_type;
478  ubuf->image_state.source = image->source;
479  ubuf->image_state.use_float = ibuf->rect_float != nullptr;
480 
481  return ubuf;
482 }
483 
484 static void ubuf_from_image_all_tiles(UndoImageBuf *ubuf, const ImBuf *ibuf)
485 {
486  ImBuf *tmpibuf = imbuf_alloc_temp_tile();
487 
488  const bool has_float = ibuf->rect_float;
489  int i = 0;
490  for (uint y_tile = 0; y_tile < ubuf->tiles_dims[1]; y_tile += 1) {
491  uint y = y_tile << ED_IMAGE_UNDO_TILE_BITS;
492  for (uint x_tile = 0; x_tile < ubuf->tiles_dims[0]; x_tile += 1) {
493  uint x = x_tile << ED_IMAGE_UNDO_TILE_BITS;
494 
495  BLI_assert(ubuf->tiles[i] == nullptr);
496  UndoImageTile *utile = utile_alloc(has_float);
497  utile->users = 1;
498  utile_init_from_imbuf(utile, x, y, ibuf, tmpibuf);
499  ubuf->tiles[i] = utile;
500 
501  i += 1;
502  }
503  }
504 
505  BLI_assert(i == ubuf->tiles_len);
506 
507  IMB_freeImBuf(tmpibuf);
508 }
509 
511 static void ubuf_ensure_compat_ibuf(const UndoImageBuf *ubuf, ImBuf *ibuf)
512 {
513  /* We could have both float and rect buffers,
514  * in this case free the float buffer if it's unused. */
515  if ((ibuf->rect_float != nullptr) && (ubuf->image_state.use_float == false)) {
517  }
518 
519  if (ibuf->x == ubuf->image_dims[0] && ibuf->y == ubuf->image_dims[1] &&
520  (ubuf->image_state.use_float ? (void *)ibuf->rect_float : (void *)ibuf->rect)) {
521  return;
522  }
523 
524  imb_freerectImbuf_all(ibuf);
525  IMB_rect_size_set(ibuf, ubuf->image_dims);
526 
527  if (ubuf->image_state.use_float) {
528  imb_addrectfloatImBuf(ibuf, 4);
529  }
530  else {
531  imb_addrectImBuf(ibuf);
532  }
533 }
534 
535 static void ubuf_free(UndoImageBuf *ubuf)
536 {
537  UndoImageBuf *ubuf_post = ubuf->post;
538  for (uint i = 0; i < ubuf->tiles_len; i++) {
539  UndoImageTile *utile = ubuf->tiles[i];
540  utile_decref(utile);
541  }
542  MEM_freeN(ubuf->tiles);
543  MEM_freeN(ubuf);
544  if (ubuf_post) {
545  ubuf_free(ubuf_post);
546  }
547 }
548 
551 /* -------------------------------------------------------------------- */
555 typedef struct UndoImageHandle {
557 
559  UndoRefID_Image image_ref;
560 
565 
570 
572 
573 static void uhandle_restore_list(ListBase *undo_handles, bool use_init)
574 {
575  ImBuf *tmpibuf = imbuf_alloc_temp_tile();
576 
577  LISTBASE_FOREACH (UndoImageHandle *, uh, undo_handles) {
578  /* Tiles only added to second set of tiles. */
579  Image *image = uh->image_ref.ptr;
580 
581  ImBuf *ibuf = BKE_image_acquire_ibuf(image, &uh->iuser, nullptr);
582  if (UNLIKELY(ibuf == nullptr)) {
583  CLOG_ERROR(&LOG, "Unable to get buffer for image '%s'", image->id.name + 2);
584  continue;
585  }
586  bool changed = false;
587  LISTBASE_FOREACH (UndoImageBuf *, ubuf_iter, &uh->buffers) {
588  UndoImageBuf *ubuf = use_init ? ubuf_iter : ubuf_iter->post;
589  ubuf_ensure_compat_ibuf(ubuf, ibuf);
590 
591  int i = 0;
592  for (uint y_tile = 0; y_tile < ubuf->tiles_dims[1]; y_tile += 1) {
593  uint y = y_tile << ED_IMAGE_UNDO_TILE_BITS;
594  for (uint x_tile = 0; x_tile < ubuf->tiles_dims[0]; x_tile += 1) {
595  uint x = x_tile << ED_IMAGE_UNDO_TILE_BITS;
596  utile_restore(ubuf->tiles[i], x, y, ibuf, tmpibuf);
597  changed = true;
598  i += 1;
599  }
600  }
601  }
602 
603  if (changed) {
605  /* TODO(@jbakker): only mark areas that are actually updated to improve performance. */
607 
608  if (ibuf->rect_float) {
609  ibuf->userflags |= IB_RECT_INVALID; /* Force recreate of char `rect` */
610  }
611  if (ibuf->mipmap[0]) {
612  ibuf->userflags |= IB_MIPMAP_INVALID; /* Force MIP-MAP recreation. */
613  }
615 
616  DEG_id_tag_update(&image->id, 0);
617  }
618  BKE_image_release_ibuf(image, ibuf, nullptr);
619  }
620 
621  IMB_freeImBuf(tmpibuf);
622 }
623 
624 static void uhandle_free_list(ListBase *undo_handles)
625 {
626  LISTBASE_FOREACH_MUTABLE (UndoImageHandle *, uh, undo_handles) {
627  LISTBASE_FOREACH_MUTABLE (UndoImageBuf *, ubuf, &uh->buffers) {
628  ubuf_free(ubuf);
629  }
630  MEM_freeN(uh);
631  }
632  BLI_listbase_clear(undo_handles);
633 }
634 
637 /* -------------------------------------------------------------------- */
644  const Image *UNUSED(image),
645  const char *ibuf_name)
646 {
647  LISTBASE_FOREACH (UndoImageBuf *, ubuf, &uh->buffers) {
648  if (STREQ(ubuf->ibuf_name, ibuf_name)) {
649  return ubuf;
650  }
651  }
652  return nullptr;
653 }
654 
656 {
657  BLI_assert(uhandle_lookup_ubuf(uh, image, ibuf->name) == nullptr);
659  BLI_addtail(&uh->buffers, ubuf);
660 
661  ubuf->post = nullptr;
662 
663  return ubuf;
664 }
665 
667 {
668  UndoImageBuf *ubuf = uhandle_lookup_ubuf(uh, image, ibuf->name);
669  if (ubuf == nullptr) {
670  ubuf = uhandle_add_ubuf(uh, image, ibuf);
671  }
672  return ubuf;
673 }
674 
676  const Image *image,
677  int tile_number)
678 {
679  LISTBASE_FOREACH (UndoImageHandle *, uh, undo_handles) {
680  if (STREQ(image->id.name + 2, uh->image_ref.name + 2) && uh->iuser.tile == tile_number) {
681  return uh;
682  }
683  }
684  return nullptr;
685 }
686 
687 static UndoImageHandle *uhandle_lookup(ListBase *undo_handles, const Image *image, int tile_number)
688 {
689  LISTBASE_FOREACH (UndoImageHandle *, uh, undo_handles) {
690  if (image == uh->image_ref.ptr && uh->iuser.tile == tile_number) {
691  return uh;
692  }
693  }
694  return nullptr;
695 }
696 
698 {
699  BLI_assert(uhandle_lookup(undo_handles, image, iuser->tile) == nullptr);
700  UndoImageHandle *uh = static_cast<UndoImageHandle *>(MEM_callocN(sizeof(*uh), __func__));
701  uh->image_ref.ptr = image;
702  uh->iuser = *iuser;
703  uh->iuser.scene = nullptr;
704  BLI_addtail(undo_handles, uh);
705  return uh;
706 }
707 
709 {
710  UndoImageHandle *uh = uhandle_lookup(undo_handles, image, iuser->tile);
711  if (uh == nullptr) {
712  uh = uhandle_add(undo_handles, image, iuser);
713  }
714  return uh;
715 }
716 
719 /* -------------------------------------------------------------------- */
725 
728 
734 
737 };
738 
744  const Image *image,
745  int tile_number,
746  const UndoImageBuf *ubuf)
747 {
748  /* Use name lookup because the pointer is cleared for previous steps. */
749  UndoImageHandle *uh_prev = uhandle_lookup_by_name(&us_prev->handles, image, tile_number);
750  if (uh_prev != nullptr) {
751  UndoImageBuf *ubuf_reference = uhandle_lookup_ubuf(uh_prev, image, ubuf->ibuf_name);
752  if (ubuf_reference) {
753  ubuf_reference = ubuf_reference->post;
754  if ((ubuf_reference->image_dims[0] == ubuf->image_dims[0]) &&
755  (ubuf_reference->image_dims[1] == ubuf->image_dims[1])) {
756  return ubuf_reference;
757  }
758  }
759  }
760  return nullptr;
761 }
762 
764 {
765  Object *obact = CTX_data_active_object(C);
766 
768  if (area && (area->spacetype == SPACE_IMAGE)) {
769  SpaceImage *sima = (SpaceImage *)area->spacedata.first;
770  if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) {
771  return true;
772  }
773  }
774  else {
775  if (obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) {
776  return true;
777  }
778  }
779  return false;
780 }
781 
783 {
784  ImageUndoStep *us = reinterpret_cast<ImageUndoStep *>(us_p);
785  /* dummy, memory is cleared anyway. */
786  us->is_encode_init = true;
788  us->paint_tile_map = MEM_new<PaintTileMap>(__func__);
789 }
790 
792  struct Main *UNUSED(bmain),
793  UndoStep *us_p)
794 {
795  /* Encoding is done along the way by adding tiles
796  * to the current 'ImageUndoStep' added by encode_init.
797  *
798  * This function ensures there are previous and current states of the image in the undo buffer.
799  */
800  ImageUndoStep *us = reinterpret_cast<ImageUndoStep *>(us_p);
801 
802  BLI_assert(us->step.data_size == 0);
803 
804  if (us->is_encode_init) {
805 
806  ImBuf *tmpibuf = imbuf_alloc_temp_tile();
807 
808  ImageUndoStep *us_reference = reinterpret_cast<ImageUndoStep *>(
810  while (us_reference && us_reference->step.type != BKE_UNDOSYS_TYPE_IMAGE) {
811  us_reference = reinterpret_cast<ImageUndoStep *>(us_reference->step.prev);
812  }
813 
814  /* Initialize undo tiles from ptiles (if they exist). */
815  for (PaintTile *ptile : us->paint_tile_map->map.values()) {
816  if (ptile->valid) {
817  UndoImageHandle *uh = uhandle_ensure(&us->handles, ptile->image, &ptile->iuser);
818  UndoImageBuf *ubuf_pre = uhandle_ensure_ubuf(uh, ptile->image, ptile->ibuf);
819 
820  UndoImageTile *utile = static_cast<UndoImageTile *>(
821  MEM_callocN(sizeof(*utile), "UndoImageTile"));
822  utile->users = 1;
823  utile->rect.pt = ptile->rect.pt;
824  ptile->rect.pt = nullptr;
825  const uint tile_index = index_from_xy(ptile->x_tile, ptile->y_tile, ubuf_pre->tiles_dims);
826 
827  BLI_assert(ubuf_pre->tiles[tile_index] == nullptr);
828  ubuf_pre->tiles[tile_index] = utile;
829  }
830  ptile_free(ptile);
831  }
832  us->paint_tile_map->map.clear();
833 
835  LISTBASE_FOREACH (UndoImageBuf *, ubuf_pre, &uh->buffers) {
836 
837  ImBuf *ibuf = BKE_image_acquire_ibuf(uh->image_ref.ptr, &uh->iuser, nullptr);
838 
839  const bool has_float = ibuf->rect_float;
840 
841  BLI_assert(ubuf_pre->post == nullptr);
842  ubuf_pre->post = ubuf_from_image_no_tiles(uh->image_ref.ptr, ibuf);
843  UndoImageBuf *ubuf_post = ubuf_pre->post;
844 
845  if (ubuf_pre->image_dims[0] != ubuf_post->image_dims[0] ||
846  ubuf_pre->image_dims[1] != ubuf_post->image_dims[1]) {
847  ubuf_from_image_all_tiles(ubuf_post, ibuf);
848  }
849  else {
850  /* Search for the previous buffer. */
851  UndoImageBuf *ubuf_reference =
852  (us_reference ? ubuf_lookup_from_reference(
853  us_reference, uh->image_ref.ptr, uh->iuser.tile, ubuf_post) :
854  nullptr);
855 
856  int i = 0;
857  for (uint y_tile = 0; y_tile < ubuf_pre->tiles_dims[1]; y_tile += 1) {
858  uint y = y_tile << ED_IMAGE_UNDO_TILE_BITS;
859  for (uint x_tile = 0; x_tile < ubuf_pre->tiles_dims[0]; x_tile += 1) {
860  uint x = x_tile << ED_IMAGE_UNDO_TILE_BITS;
861 
862  if ((ubuf_reference != nullptr) &&
863  ((ubuf_pre->tiles[i] == nullptr) ||
864  /* In this case the paint stroke as has added a tile
865  * which we have a duplicate reference available. */
866  (ubuf_pre->tiles[i]->users == 1))) {
867  if (ubuf_pre->tiles[i] != nullptr) {
868  /* If we have a reference, re-use this single use tile for the post state. */
869  BLI_assert(ubuf_pre->tiles[i]->users == 1);
870  ubuf_post->tiles[i] = ubuf_pre->tiles[i];
871  ubuf_pre->tiles[i] = nullptr;
872  utile_init_from_imbuf(ubuf_post->tiles[i], x, y, ibuf, tmpibuf);
873  }
874  else {
875  BLI_assert(ubuf_post->tiles[i] == nullptr);
876  ubuf_post->tiles[i] = ubuf_reference->tiles[i];
877  ubuf_post->tiles[i]->users += 1;
878  }
879  BLI_assert(ubuf_pre->tiles[i] == nullptr);
880  ubuf_pre->tiles[i] = ubuf_reference->tiles[i];
881  ubuf_pre->tiles[i]->users += 1;
882 
883  BLI_assert(ubuf_pre->tiles[i] != nullptr);
884  BLI_assert(ubuf_post->tiles[i] != nullptr);
885  }
886  else {
887  UndoImageTile *utile = utile_alloc(has_float);
888  utile_init_from_imbuf(utile, x, y, ibuf, tmpibuf);
889 
890  if (ubuf_pre->tiles[i] != nullptr) {
891  ubuf_post->tiles[i] = utile;
892  utile->users = 1;
893  }
894  else {
895  ubuf_pre->tiles[i] = utile;
896  ubuf_post->tiles[i] = utile;
897  utile->users = 2;
898  }
899  }
900  BLI_assert(ubuf_pre->tiles[i] != nullptr);
901  BLI_assert(ubuf_post->tiles[i] != nullptr);
902  i += 1;
903  }
904  }
905  BLI_assert(i == ubuf_pre->tiles_len);
906  BLI_assert(i == ubuf_post->tiles_len);
907  }
908  BKE_image_release_ibuf(uh->image_ref.ptr, ibuf, nullptr);
909  }
910  }
911 
912  IMB_freeImBuf(tmpibuf);
913 
914  /* Useful to debug tiles are stored correctly. */
915  if (false) {
916  uhandle_restore_list(&us->handles, false);
917  }
918  }
919  else {
920  BLI_assert(C != nullptr);
921  /* Happens when switching modes. */
924  us->paint_mode = paint_mode;
925  }
926 
927  us_p->is_applied = true;
928 
929  return true;
930 }
931 
932 static void image_undosys_step_decode_undo_impl(ImageUndoStep *us, bool is_final)
933 {
934  BLI_assert(us->step.is_applied == true);
935  uhandle_restore_list(&us->handles, !is_final);
936  us->step.is_applied = false;
937 }
938 
940 {
941  BLI_assert(us->step.is_applied == false);
942  uhandle_restore_list(&us->handles, false);
943  us->step.is_applied = true;
944 }
945 
946 static void image_undosys_step_decode_undo(ImageUndoStep *us, bool is_final)
947 {
948  /* Walk forward over any applied steps of same type,
949  * then walk back in the next loop, un-applying them. */
950  ImageUndoStep *us_iter = us;
951  while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) {
952  if (us_iter->step.next->is_applied == false) {
953  break;
954  }
955  us_iter = (ImageUndoStep *)us_iter->step.next;
956  }
957  while (us_iter != us || (!is_final && us_iter == us)) {
958  BLI_assert(us_iter->step.type == us->step.type); /* Previous loop ensures this. */
959  image_undosys_step_decode_undo_impl(us_iter, is_final);
960  if (us_iter == us) {
961  break;
962  }
963  us_iter = (ImageUndoStep *)us_iter->step.prev;
964  }
965 }
966 
968 {
969  ImageUndoStep *us_iter = us;
970  while (us_iter->step.prev && (us_iter->step.prev->type == us_iter->step.type)) {
971  if (us_iter->step.prev->is_applied == true) {
972  break;
973  }
974  us_iter = (ImageUndoStep *)us_iter->step.prev;
975  }
976  while (us_iter && (us_iter->step.is_applied == false)) {
978  if (us_iter == us) {
979  break;
980  }
981  us_iter = (ImageUndoStep *)us_iter->step.next;
982  }
983 }
984 
986  struct bContext *C, struct Main *bmain, UndoStep *us_p, const eUndoStepDir dir, bool is_final)
987 {
988  /* NOTE: behavior for undo/redo closely matches sculpt undo. */
989  BLI_assert(dir != STEP_INVALID);
990 
991  ImageUndoStep *us = reinterpret_cast<ImageUndoStep *>(us_p);
992  if (dir == STEP_UNDO) {
993  image_undosys_step_decode_undo(us, is_final);
994  }
995  else if (dir == STEP_REDO) {
997  }
998 
999  if (us->paint_mode == PAINT_MODE_TEXTURE_3D) {
1000  ED_object_mode_set_ex(C, OB_MODE_TEXTURE_PAINT, false, nullptr);
1001  }
1002 
1003  /* Refresh texture slots. */
1004  ED_editors_init_for_undo(bmain);
1005 }
1006 
1008 {
1009  ImageUndoStep *us = (ImageUndoStep *)us_p;
1010  uhandle_free_list(&us->handles);
1011 
1012  /* Typically this map will have been cleared. */
1013  MEM_delete(us->paint_tile_map);
1014  us->paint_tile_map = nullptr;
1015 }
1016 
1018  UndoTypeForEachIDRefFn foreach_ID_ref_fn,
1019  void *user_data)
1020 {
1021  ImageUndoStep *us = reinterpret_cast<ImageUndoStep *>(us_p);
1022  LISTBASE_FOREACH (UndoImageHandle *, uh, &us->handles) {
1023  foreach_ID_ref_fn(user_data, ((UndoRefID *)&uh->image_ref));
1024  }
1025 }
1026 
1028 {
1029  ut->name = "Image";
1030  ut->poll = image_undosys_poll;
1035 
1037 
1038  /* NOTE: this is actually a confusing case, since it expects a valid context, but only in a
1039  * specific case, see `image_undosys_step_encode` code. We cannot specify
1040  * `UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE` though, as it can be called with a NULL context by
1041  * current code. */
1043 
1044  ut->step_size = sizeof(ImageUndoStep);
1045 }
1046 
1049 /* -------------------------------------------------------------------- */
1062 {
1063  UndoStack *ustack = ED_undo_stack_get();
1064  UndoStep *us_prev = ustack->step_init;
1066  ImageUndoStep *us = reinterpret_cast<ImageUndoStep *>(us_p);
1067  /* We should always have an undo push started when accessing tiles,
1068  * not doing this means we won't have paint_mode correctly set. */
1069  BLI_assert(us_p == us_prev);
1070  if (us_p != us_prev) {
1071  /* Fallback value until we can be sure this never happens. */
1073  }
1074  return us->paint_tile_map;
1075 }
1076 
1078 {
1079  PaintTileMap *paint_tile_map = reinterpret_cast<ImageUndoStep *>(us)->paint_tile_map;
1080  ptile_restore_runtime_map(paint_tile_map);
1081  ptile_invalidate_map(paint_tile_map);
1082 }
1083 
1084 static ImageUndoStep *image_undo_push_begin(const char *name, int paint_mode)
1085 {
1086  UndoStack *ustack = ED_undo_stack_get();
1087  bContext *C = nullptr; /* special case, we never read from this. */
1089  ImageUndoStep *us = reinterpret_cast<ImageUndoStep *>(us_p);
1091  us->paint_mode = (ePaintMode)paint_mode;
1092  return us;
1093 }
1094 
1095 void ED_image_undo_push_begin(const char *name, int paint_mode)
1096 {
1097  image_undo_push_begin(name, paint_mode);
1098 }
1099 
1101  Image *image,
1102  ImBuf *ibuf,
1103  ImageUser *iuser)
1104 {
1106 
1108  UndoImageHandle *uh = uhandle_ensure(&us->handles, image, iuser);
1109  UndoImageBuf *ubuf_pre = uhandle_ensure_ubuf(uh, image, ibuf);
1110  BLI_assert(ubuf_pre->post == nullptr);
1111 
1112  ImageUndoStep *us_reference = reinterpret_cast<ImageUndoStep *>(
1114  while (us_reference && us_reference->step.type != BKE_UNDOSYS_TYPE_IMAGE) {
1115  us_reference = reinterpret_cast<ImageUndoStep *>(us_reference->step.prev);
1116  }
1117  UndoImageBuf *ubuf_reference = (us_reference ? ubuf_lookup_from_reference(
1118  us_reference, image, iuser->tile, ubuf_pre) :
1119  nullptr);
1120 
1121  if (ubuf_reference) {
1122  memcpy(ubuf_pre->tiles, ubuf_reference->tiles, sizeof(*ubuf_pre->tiles) * ubuf_pre->tiles_len);
1123  for (uint32_t i = 0; i < ubuf_pre->tiles_len; i++) {
1124  UndoImageTile *utile = ubuf_pre->tiles[i];
1125  utile->users += 1;
1126  }
1127  }
1128  else {
1129  ubuf_from_image_all_tiles(ubuf_pre, ibuf);
1130  }
1131 }
1132 
1134 {
1135  UndoStack *ustack = ED_undo_stack_get();
1136  BKE_undosys_step_push(ustack, nullptr, nullptr);
1139 }
1140 
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:738
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1353
void BKE_image_release_ibuf(struct Image *ima, struct ImBuf *ibuf, void *lock)
struct ImBuf * BKE_image_acquire_ibuf(struct Image *ima, struct ImageUser *iuser, void **r_lock)
void BKE_image_partial_update_mark_full_update(struct Image *image)
Mark the whole image to be updated.
void BKE_image_free_gputextures(struct Image *ima)
Definition: image_gpu.cc:516
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:67
@ PAINT_MODE_TEXTURE_3D
Definition: BKE_paint.h:73
@ PAINT_MODE_SCULPT
Definition: BKE_paint.h:68
@ PAINT_MODE_TEXTURE_2D
Definition: BKE_paint.h:75
@ UNDOTYPE_FLAG_DECODE_ACTIVE_STEP
UndoStep * BKE_undosys_step_push_init_with_type(UndoStack *ustack, struct bContext *C, const char *name, const UndoType *ut)
Definition: undo_system.c:449
eUndoPushReturn BKE_undosys_step_push(UndoStack *ustack, struct bContext *C, const char *name)
Definition: undo_system.c:593
UndoStep * BKE_undosys_stack_init_or_active_with_type(UndoStack *ustack, const UndoType *ut)
Definition: undo_system.c:373
eUndoStepDir
@ STEP_INVALID
@ STEP_UNDO
@ STEP_REDO
#define BKE_undosys_stack_limit_steps_and_memory_defaults(ustack)
const UndoType * BKE_UNDOSYS_TYPE_IMAGE
Definition: undo_system.c:53
void(* UndoTypeForEachIDRefFn)(void *user_data, struct UndoRefID *id_ref)
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:354
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:273
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
MINLINE int square_i(int a)
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
unsigned int uint
Definition: BLI_sys_types.h:67
unsigned short ushort
Definition: BLI_sys_types.h:68
pthread_spinlock_t SpinLock
Definition: BLI_threads.h:110
void BLI_spin_init(SpinLock *spin)
Definition: threads.cc:419
void BLI_spin_unlock(SpinLock *spin)
Definition: threads.cc:452
void BLI_spin_lock(SpinLock *spin)
Definition: threads.cc:433
void BLI_spin_end(SpinLock *spin)
Definition: threads.cc:467
#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:190
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:191
#define ED_IMAGE_UNDO_TILE_NUMBER(size)
Definition: ED_paint.h:106
#define ED_IMAGE_UNDO_TILE_SIZE
Definition: ED_paint.h:105
#define ED_IMAGE_UNDO_TILE_BITS
Definition: ED_paint.h:104
struct UndoStack * ED_undo_stack_get(void)
Definition: ed_undo.c:473
void ED_editors_init_for_undo(struct Main *bmain)
Definition: ed_util.c:60
_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:80
struct ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
Definition: allocimbuf.c:500
bool imb_addrectfloatImBuf(struct ImBuf *ibuf, const unsigned int channels)
Definition: allocimbuf.c:367
void IMB_rect_size_set(struct ImBuf *ibuf, const uint size[2])
Definition: rectop.c:285
void imb_freerectImbuf_all(struct ImBuf *ibuf)
Definition: allocimbuf.c:182
bool imb_addrectImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:387
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:25
void clear()
Definition: BLI_map.hh:963
ValueIterator values() const
Definition: BLI_map.hh:840
const Value * lookup_ptr(const Key &key) const
Definition: BLI_map.hh:463
auto add_or_modify(const Key &key, const CreateValueF &create_value, const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
Definition: BLI_map.hh:436
void * user_data
depth_tx normal_tx diffuse_light_tx specular_light_tx volume_light_tx environment_tx ambient_occlusion_tx aov_value_tx in_weight_img image(1, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D_ARRAY, "out_weight_img") .image(3
void IMB_freeImBuf(ImBuf *UNUSED(ibuf))
void * ED_image_paint_tile_find(PaintTileMap *paint_tile_map, Image *image, ImBuf *ibuf, ImageUser *iuser, int x_tile, int y_tile, ushort **r_mask, bool validate)
Definition: image_undo.cc:158
static void utile_decref(UndoImageTile *utile)
Definition: image_undo.cc:419
static bool image_undosys_step_encode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p)
Definition: image_undo.cc:791
static void uhandle_restore_list(ListBase *undo_handles, bool use_init)
Definition: image_undo.cc:573
static UndoImageTile * utile_alloc(bool has_float)
Definition: image_undo.cc:362
static void ptile_free(PaintTile *ptile)
Definition: image_undo.cc:129
PaintTileMap * ED_image_paint_tile_map_get(void)
Definition: image_undo.cc:1061
static void ptile_invalidate_map(PaintTileMap *paint_tile_map)
Definition: image_undo.cc:151
static void image_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p)
Definition: image_undo.cc:782
static ImageUndoStep * image_undo_push_begin(const char *name, int paint_mode)
Definition: image_undo.cc:1084
static void image_undosys_step_decode(struct bContext *C, struct Main *bmain, UndoStep *us_p, const eUndoStepDir dir, bool is_final)
Definition: image_undo.cc:985
static UndoImageHandle * uhandle_lookup_by_name(ListBase *undo_handles, const Image *image, int tile_number)
Definition: image_undo.cc:675
void ED_image_undo_push_begin_with_image(const char *name, Image *image, ImBuf *ibuf, ImageUser *iuser)
Definition: image_undo.cc:1100
static void uhandle_free_list(ListBase *undo_handles)
Definition: image_undo.cc:624
static void utile_init_from_imbuf(UndoImageTile *utile, const uint32_t x, const uint32_t y, const ImBuf *ibuf, ImBuf *tmpibuf)
Definition: image_undo.cc:377
void ED_image_undo_push_begin(const char *name, int paint_mode)
Definition: image_undo.cc:1095
static void ptile_restore_runtime_map(PaintTileMap *paint_tile_map)
Definition: image_undo.cc:292
void ED_image_undosys_type(UndoType *ut)
Definition: image_undo.cc:1027
static UndoImageBuf * ubuf_from_image_no_tiles(Image *image, const ImBuf *ibuf)
Definition: image_undo.cc:462
static void image_undosys_step_decode_undo(ImageUndoStep *us, bool is_final)
Definition: image_undo.cc:946
void ED_image_paint_tile_lock_end(void)
Definition: image_undo.cc:69
void ED_image_paint_tile_lock_init(void)
Definition: image_undo.cc:64
static void image_undosys_foreach_ID_ref(UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
Definition: image_undo.cc:1017
static UndoImageBuf * uhandle_ensure_ubuf(UndoImageHandle *uh, Image *image, ImBuf *ibuf)
Definition: image_undo.cc:666
static UndoImageBuf * uhandle_add_ubuf(UndoImageHandle *uh, Image *image, ImBuf *ibuf)
Definition: image_undo.cc:655
static void image_undosys_step_decode_redo(ImageUndoStep *us)
Definition: image_undo.cc:967
static UndoImageHandle * uhandle_add(ListBase *undo_handles, Image *image, ImageUser *iuser)
Definition: image_undo.cc:697
void ED_image_undo_push_end(void)
Definition: image_undo.cc:1133
static UndoImageHandle * uhandle_ensure(ListBase *undo_handles, Image *image, ImageUser *iuser)
Definition: image_undo.cc:708
static void ubuf_ensure_compat_ibuf(const UndoImageBuf *ubuf, ImBuf *ibuf)
Definition: image_undo.cc:511
static void image_undosys_step_free(UndoStep *us_p)
Definition: image_undo.cc:1007
void * ED_image_paint_tile_push(PaintTileMap *paint_tile_map, 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.cc:192
static void image_undosys_step_decode_redo_impl(ImageUndoStep *us)
Definition: image_undo.cc:939
static bool image_undosys_poll(bContext *C)
Definition: image_undo.cc:763
static void image_undosys_step_decode_undo_impl(ImageUndoStep *us, bool is_final)
Definition: image_undo.cc:932
struct UndoImageHandle UndoImageHandle
static uint32_t index_from_xy(uint32_t tile_x, uint32_t tile_y, const uint32_t tiles_dims[2])
Definition: image_undo.cc:347
static CLG_LogRef LOG
Definition: image_undo.cc:53
static UndoImageBuf * uhandle_lookup_ubuf(UndoImageHandle *uh, const Image *UNUSED(image), const char *ibuf_name)
Definition: image_undo.cc:643
struct UndoImageBuf UndoImageBuf
void ED_image_undo_restore(UndoStep *us)
Definition: image_undo.cc:1077
static void ubuf_free(UndoImageBuf *ubuf)
Definition: image_undo.cc:535
static UndoImageHandle * uhandle_lookup(ListBase *undo_handles, const Image *image, int tile_number)
Definition: image_undo.cc:687
static void ubuf_from_image_all_tiles(UndoImageBuf *ubuf, const ImBuf *ibuf)
Definition: image_undo.cc:484
static ImBuf * imbuf_alloc_temp_tile()
Definition: image_undo.cc:86
static UndoImageBuf * ubuf_lookup_from_reference(ImageUndoStep *us_prev, const Image *image, int tile_number, const UndoImageBuf *ubuf)
Definition: image_undo.cc:743
static SpinLock paint_tiles_lock
Definition: image_undo.cc:62
static void utile_restore(const UndoImageTile *utile, const uint x, const uint y, ImBuf *ibuf, ImBuf *tmpibuf)
Definition: image_undo.cc:399
const int tile_index
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
static void area(int d1, int d2, int e1, int e2, float weights[2])
uint64_t get_default_hash_4(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4)
Definition: BLI_hash.hh:240
unsigned short uint16_t
Definition: stdint.h:79
unsigned int uint32_t
Definition: stdint.h:80
unsigned __int64 uint64_t
Definition: stdint.h:90
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.cc:736
ListBase handles
Definition: image_undo.cc:727
UndoStep step
Definition: image_undo.cc:724
PaintTileMap * paint_tile_map
Definition: image_undo.cc:733
bool is_encode_init
Definition: image_undo.cc:735
struct Scene * scene
Definition: BKE_main.h:121
bool operator==(const PaintTileKey &other) const
Definition: image_undo.cc:103
Image * image
Definition: image_undo.cc:94
uint64_t hash() const
Definition: image_undo.cc:99
ImBuf * ibuf
Definition: image_undo.cc:95
blender::Map< PaintTileKey, PaintTile * > map
Definition: image_undo.cc:141
uint16_t * mask
Definition: image_undo.cc:123
Image * image
Definition: image_undo.cc:111
bool use_float
Definition: image_undo.cc:125
void * pt
Definition: image_undo.cc:121
uint32_t * uint
Definition: image_undo.cc:120
union PaintTile::@530 rect
ImageUser iuser
Definition: image_undo.cc:117
bool valid
Definition: image_undo.cc:124
float * fp
Definition: image_undo.cc:119
ImBuf * ibuf
Definition: image_undo.cc:112
struct UndoImageBuf::@532 image_state
UndoImageTile ** tiles
Definition: image_undo.cc:445
struct UndoImageBuf * prev
Definition: image_undo.cc:436
char ibuf_name[IMB_FILENAME_SIZE]
Definition: image_undo.cc:443
struct UndoImageBuf * post
Definition: image_undo.cc:441
struct UndoImageBuf * next
Definition: image_undo.cc:436
uint32_t tiles_dims[2]
Definition: image_undo.cc:449
uint32_t image_dims[2]
Definition: image_undo.cc:451
uint32_t tiles_len
Definition: image_undo.cc:448
ImageUser iuser
Definition: image_undo.cc:564
UndoRefID_Image image_ref
Definition: image_undo.cc:559
ListBase buffers
Definition: image_undo.cc:569
struct UndoImageHandle * next
Definition: image_undo.cc:556
struct UndoImageHandle * prev
Definition: image_undo.cc:556
union UndoImageTile::@531 rect
uint32_t * uint_ptr
Definition: image_undo.cc:356
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, 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:150