Undo System: remove accumulate/store modes
[blender.git] / source / blender / editors / sculpt_paint / paint_image_undo.c
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
16 /** \file blender/editors/sculpt_paint/paint_image_undo.c
17  *  \ingroup edsculpt
18  */
19
20 #include "MEM_guardedalloc.h"
21
22 #include "BLI_math.h"
23 #include "BLI_blenlib.h"
24 #include "BLI_utildefines.h"
25 #include "BLI_threads.h"
26
27 #include "DNA_image_types.h"
28 #include "DNA_windowmanager_types.h"
29 #include "DNA_object_types.h"
30 #include "DNA_screen_types.h"
31 #include "DNA_space_types.h"
32 #include "DNA_workspace_types.h"
33
34 #include "IMB_imbuf.h"
35 #include "IMB_imbuf_types.h"
36
37 #include "BKE_context.h"
38 #include "BKE_image.h"
39 #include "BKE_paint.h"
40 #include "BKE_undo_system.h"
41
42 #include "DEG_depsgraph.h"
43
44 #include "ED_paint.h"
45 #include "ED_undo.h"
46 #include "ED_util.h"
47 #include "ED_object.h"
48
49 #include "GPU_draw.h"
50
51 #include "paint_intern.h"
52
53 /* -------------------------------------------------------------------- */
54 /** \name Undo Conversion
55  * \{ */
56
57 typedef struct UndoImageTile {
58         struct UndoImageTile *next, *prev;
59
60         char ibufname[IMB_FILENAME_SIZE];
61
62         union {
63                 float        *fp;
64                 unsigned int *uint;
65                 void         *pt;
66         } rect;
67
68         unsigned short *mask;
69
70         int x, y;
71
72         Image *ima;
73         short source, use_float;
74         char gen_type;
75         bool valid;
76
77         size_t undo_size;
78 } UndoImageTile;
79
80 /* this is a static resource for non-globality,
81  * Maybe it should be exposed as part of the
82  * paint operation, but for now just give a public interface */
83 static SpinLock undolock;
84
85 void image_undo_init_locks(void)
86 {
87         BLI_spin_init(&undolock);
88 }
89
90 void image_undo_end_locks(void)
91 {
92         BLI_spin_end(&undolock);
93 }
94
95 /* UNDO */
96 typedef enum {
97         COPY = 0,
98         RESTORE = 1,
99         RESTORE_COPY = 2,
100 } CopyMode;
101
102 static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, CopyMode mode)
103 {
104         if (mode == COPY) {
105                 /* copy or swap contents of tile->rect and region in ibuf->rect */
106                 IMB_rectcpy(
107                         tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE,
108                         tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
109
110                 if (ibuf->rect_float) {
111                         SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
112                 }
113                 else {
114                         SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
115                 }
116         }
117         else {
118                 if (mode == RESTORE_COPY) {
119                         IMB_rectcpy(
120                                 tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE,
121                                 tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
122                 }
123                 /* swap to the tmpbuf for easy copying */
124                 if (ibuf->rect_float) {
125                         SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
126                 }
127                 else {
128                         SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
129                 }
130
131                 IMB_rectcpy(
132                         ibuf, tmpibuf, tile->x * IMAPAINT_TILE_SIZE,
133                         tile->y * IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
134
135                 if (mode == RESTORE) {
136                         if (ibuf->rect_float) {
137                                 SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
138                         }
139                         else {
140                                 SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
141                         }
142                 }
143         }
144 }
145
146 void *image_undo_find_tile(
147         ListBase *undo_tiles,
148         Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask, bool validate)
149 {
150         UndoImageTile *tile;
151         short use_float = ibuf->rect_float ? 1 : 0;
152
153         for (tile = undo_tiles->first; tile; tile = tile->next) {
154                 if (tile->x == x_tile && tile->y == y_tile && ima->gen_type == tile->gen_type && ima->source == tile->source) {
155                         if (tile->use_float == use_float) {
156                                 if (STREQ(tile->ibufname, ibuf->name)) {
157                                         if (mask) {
158                                                 /* allocate mask if requested */
159                                                 if (!tile->mask) {
160                                                         tile->mask = MEM_callocN(
161                                                                 sizeof(unsigned short) * IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE,
162                                                                 "UndoImageTile.mask");
163                                                 }
164
165                                                 *mask = tile->mask;
166                                         }
167                                         if (validate) {
168                                                 tile->valid = true;
169                                         }
170                                         return tile->rect.pt;
171                                 }
172                         }
173                 }
174         }
175
176         return NULL;
177 }
178
179 void *image_undo_push_tile(
180         ListBase *undo_tiles,
181         Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile,
182         unsigned short **mask, bool **valid, bool proj, bool find_prev)
183 {
184         UndoImageTile *tile;
185         int allocsize;
186         short use_float = ibuf->rect_float ? 1 : 0;
187         void *data;
188
189         /* check if tile is already pushed */
190
191         /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */
192         if (find_prev) {
193                 data = image_undo_find_tile(undo_tiles, ima, ibuf, x_tile, y_tile, mask, true);
194                 if (data) {
195                         return data;
196                 }
197         }
198
199         if (*tmpibuf == NULL) {
200                 *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
201         }
202
203         tile = MEM_callocN(sizeof(UndoImageTile), "UndoImageTile");
204         tile->x = x_tile;
205         tile->y = y_tile;
206
207         /* add mask explicitly here */
208         if (mask) {
209                 *mask = tile->mask = MEM_callocN(
210                         sizeof(unsigned short) * IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE,
211                         "UndoImageTile.mask");
212         }
213         allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
214         allocsize *= (ibuf->rect_float) ? sizeof(float) : sizeof(char);
215         tile->rect.pt = MEM_mapallocN(allocsize, "UndeImageTile.rect");
216
217         BLI_strncpy(tile->ibufname, ibuf->name, sizeof(tile->ibufname));
218
219         tile->gen_type = ima->gen_type;
220         tile->source = ima->source;
221         tile->use_float = use_float;
222         tile->valid = true;
223         tile->ima = ima;
224
225         if (valid) {
226                 *valid = &tile->valid;
227         }
228         undo_copy_tile(tile, *tmpibuf, ibuf, COPY);
229
230         if (proj) {
231                 BLI_spin_lock(&undolock);
232         }
233         BLI_addtail(undo_tiles, tile);
234
235         if (proj) {
236                 BLI_spin_unlock(&undolock);
237         }
238         return tile->rect.pt;
239 }
240
241 void image_undo_remove_masks(void)
242 {
243         ListBase *undo_tiles = ED_image_undo_get_tiles();
244         UndoImageTile *tile;
245
246         for (tile = undo_tiles->first; tile; tile = tile->next) {
247                 if (tile->mask) {
248                         MEM_freeN(tile->mask);
249                         tile->mask = NULL;
250                 }
251         }
252 }
253
254 static void image_undo_restore_runtime(ListBase *lb)
255 {
256         ImBuf *ibuf, *tmpibuf;
257         UndoImageTile *tile;
258
259         tmpibuf = IMB_allocImBuf(
260                 IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32,
261                 IB_rectfloat | IB_rect);
262
263         for (tile = lb->first; tile; tile = tile->next) {
264                 Image *ima = tile->ima;
265                 ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
266
267                 undo_copy_tile(tile, tmpibuf, ibuf, RESTORE);
268
269                 GPU_free_image(ima); /* force OpenGL reload (maybe partial update will operate better?) */
270                 if (ibuf->rect_float) {
271                         ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
272                 }
273                 if (ibuf->mipmap[0]) {
274                         ibuf->userflags |= IB_MIPMAP_INVALID;  /* force mipmap recreatiom */
275                 }
276                 ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
277
278                 BKE_image_release_ibuf(ima, ibuf, NULL);
279         }
280
281         IMB_freeImBuf(tmpibuf);
282 }
283
284 static void image_undo_restore_list(ListBase *lb, struct UndoIDPtrMap *id_map)
285 {
286         ImBuf *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
287
288         /* Store last found image. */
289         ID *image_prev[2] = {NULL};
290
291         for (UndoImageTile *tile = lb->first; tile; tile = tile->next) {
292                 short use_float;
293
294                 Image *ima = (Image *)BKE_undosys_ID_map_lookup_with_prev(id_map, &tile->ima->id, image_prev);
295
296                 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
297
298                 if (ima && ibuf && !STREQ(tile->ibufname, ibuf->name)) {
299                         /* current ImBuf filename was changed, probably current frame
300                          * was changed when painting on image sequence, rather than storing
301                          * full image user (which isn't so obvious, btw) try to find ImBuf with
302                          * matched file name in list of already loaded images */
303
304                         BKE_image_release_ibuf(ima, ibuf, NULL);
305
306                         ibuf = BKE_image_get_ibuf_with_name(ima, tile->ibufname);
307                 }
308
309                 if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) {
310                         BKE_image_release_ibuf(ima, ibuf, NULL);
311                         continue;
312                 }
313
314                 if (ima->gen_type != tile->gen_type || ima->source != tile->source) {
315                         BKE_image_release_ibuf(ima, ibuf, NULL);
316                         continue;
317                 }
318
319                 use_float = ibuf->rect_float ? 1 : 0;
320
321                 if (use_float != tile->use_float) {
322                         BKE_image_release_ibuf(ima, ibuf, NULL);
323                         continue;
324                 }
325
326                 undo_copy_tile(tile, tmpibuf, ibuf, RESTORE_COPY);
327
328                 GPU_free_image(ima); /* force OpenGL reload */
329                 if (ibuf->rect_float) {
330                         ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
331                 }
332                 if (ibuf->mipmap[0]) {
333                         ibuf->userflags |= IB_MIPMAP_INVALID;  /* force mipmap recreatiom */
334                 }
335                 ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
336
337                 DEG_id_tag_update(&ima->id, 0);
338
339                 BKE_image_release_ibuf(ima, ibuf, NULL);
340         }
341
342         IMB_freeImBuf(tmpibuf);
343 }
344
345 static void image_undo_free_list(ListBase *lb)
346 {
347         for (UndoImageTile *tile = lb->first, *tile_next; tile; tile = tile_next) {
348                 tile_next = tile->next;
349                 MEM_freeN(tile->rect.pt);
350                 MEM_freeN(tile);
351         }
352 }
353
354 static void image_undo_invalidate(void)
355 {
356         UndoImageTile *tile;
357         ListBase *lb = ED_image_undo_get_tiles();
358
359         for (tile = lb->first; tile; tile = tile->next) {
360                 tile->valid = false;
361         }
362 }
363
364 /** \} */
365
366 /* -------------------------------------------------------------------- */
367 /** \name Implements ED Undo System
368  * \{ */
369
370 typedef struct ImageUndoStep {
371         UndoStep step;
372         ListBase tiles;
373         bool is_encode_init;
374         ePaintMode paint_mode;
375
376         /* Use for all ID lookups (can be NULL). */
377         struct UndoIDPtrMap *id_map;
378 } ImageUndoStep;
379
380 static void image_undosys_step_encode_store_ids(ImageUndoStep *us)
381 {
382         us->id_map = BKE_undosys_ID_map_create();
383
384         ID *image_prev = NULL;
385         for (UndoImageTile *tile = us->tiles.first; tile; tile = tile->next) {
386                 BKE_undosys_ID_map_add_with_prev(us->id_map, &tile->ima->id, &image_prev);
387         }
388 }
389
390 /* Restore at runtime. */
391 #if 0
392 static void paint_undosys_step_decode_restore_ids(ImageUndoStep *us)
393 {
394         ID *image_prev[2] = {NULL};
395         for (UndoImageTile *tile = us->tiles.first; tile; tile = tile->next) {
396                 tile->ima = (Image *)BKE_undosys_ID_map_lookup_with_prev(us->id_map, &tile->ima->id, image_prev);
397         }
398 }
399 #endif
400
401 static bool image_undosys_poll(bContext *C)
402 {
403         Object *obact = CTX_data_active_object(C);
404
405         ScrArea *sa = CTX_wm_area(C);
406         if (sa && (sa->spacetype == SPACE_IMAGE)) {
407                 SpaceImage *sima = (SpaceImage *)sa->spacedata.first;
408                 if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) ||
409                     (sima->mode == SI_MODE_PAINT))
410                 {
411                         return true;
412                 }
413         }
414         else {
415                 if (obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) {
416                         return true;
417                 }
418         }
419         return false;
420 }
421
422 static void image_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p)
423 {
424         ImageUndoStep *us = (ImageUndoStep *)us_p;
425         /* dummy, memory is cleared anyway. */
426         us->is_encode_init = true;
427         BLI_listbase_clear(&us->tiles);
428 }
429
430 static bool image_undosys_step_encode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p)
431 {
432         /* dummy, encoding is done along the way by adding tiles
433          * to the current 'ImageUndoStep' added by encode_init. */
434         ImageUndoStep *us = (ImageUndoStep *)us_p;
435
436         BLI_assert(us->step.data_size == 0);
437
438         int allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
439
440         if (us->is_encode_init) {
441                 /* first dispose of invalid tiles (may happen due to drag dot for instance) */
442                 for (UndoImageTile *tile = us->tiles.first; tile;) {
443                         if (!tile->valid) {
444                                 UndoImageTile *tmp_tile = tile->next;
445                                 MEM_freeN(tile->rect.pt);
446                                 BLI_freelinkN(&us->tiles, tile);
447                                 tile = tmp_tile;
448                         }
449                         else {
450                                 us->step.data_size += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char));
451                                 tile = tile->next;
452                         }
453                 }
454         }
455         else {
456                 /* Happens when switching modes. */
457                 ePaintMode paint_mode = BKE_paintmode_get_active_from_context(C);
458                 BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D));
459                 us->paint_mode = paint_mode;
460         }
461
462         image_undosys_step_encode_store_ids(us);
463
464         us_p->is_applied = true;
465
466         return true;
467 }
468
469
470 static void image_undosys_step_decode_undo_impl(ImageUndoStep *us)
471 {
472         BLI_assert(us->step.is_applied == true);
473         image_undo_restore_list(&us->tiles, us->id_map);
474         us->step.is_applied = false;
475 }
476
477 static void image_undosys_step_decode_redo_impl(ImageUndoStep *us)
478 {
479         BLI_assert(us->step.is_applied == false);
480         image_undo_restore_list(&us->tiles, us->id_map);
481         us->step.is_applied = true;
482 }
483
484 static void image_undosys_step_decode_undo(ImageUndoStep *us)
485 {
486         ImageUndoStep *us_iter = us;
487         while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) {
488                 if (us_iter->step.next->is_applied == false) {
489                         break;
490                 }
491                 us_iter = (ImageUndoStep *)us_iter->step.next;
492         }
493         while (us_iter != us) {
494                 image_undosys_step_decode_undo_impl(us_iter);
495                 us_iter = (ImageUndoStep *)us_iter->step.prev;
496         }
497 }
498
499 static void image_undosys_step_decode_redo(ImageUndoStep *us)
500 {
501         ImageUndoStep *us_iter = us;
502         while (us_iter->step.prev && (us_iter->step.prev->type == us_iter->step.type)) {
503                 if (us_iter->step.prev->is_applied == true) {
504                         break;
505                 }
506                 us_iter = (ImageUndoStep *)us_iter->step.prev;
507         }
508         while (us_iter && (us_iter->step.is_applied == false)) {
509                 image_undosys_step_decode_redo_impl(us_iter);
510                 if (us_iter == us) {
511                         break;
512                 }
513                 us_iter = (ImageUndoStep *)us_iter->step.next;
514         }
515 }
516
517 static void image_undosys_step_decode(struct bContext *C, struct Main *bmain, UndoStep *us_p, int dir)
518 {
519         ImageUndoStep *us = (ImageUndoStep *)us_p;
520 #if 0
521         paint_undosys_step_decode_restore_ids(us);
522 #endif
523
524         if (dir < 0) {
525                 image_undosys_step_decode_undo(us);
526         }
527         else {
528                 image_undosys_step_decode_redo(us);
529         }
530
531         if (us->paint_mode == PAINT_MODE_TEXTURE_3D) {
532                 ED_object_mode_set(C, OB_MODE_TEXTURE_PAINT);
533         }
534
535         /* Refresh texture slots. */
536         ED_editors_init_for_undo(bmain);
537 }
538
539 static void image_undosys_step_free(UndoStep *us_p)
540 {
541         ImageUndoStep *us = (ImageUndoStep *)us_p;
542         image_undo_free_list(&us->tiles);
543         BKE_undosys_ID_map_destroy(us->id_map);
544 }
545
546 static void image_undosys_foreach_ID_ref(
547         UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
548 {
549         ImageUndoStep *us = (ImageUndoStep *)us_p;
550         if (us->id_map != NULL) {
551                 BKE_undosys_ID_map_foreach_ID_ref(us->id_map, foreach_ID_ref_fn, user_data);
552         }
553 }
554
555 /* Export for ED_undo_sys. */
556 void ED_image_undosys_type(UndoType *ut)
557 {
558         ut->name = "Image";
559         ut->poll = image_undosys_poll;
560         ut->step_encode_init = image_undosys_step_encode_init;
561         ut->step_encode = image_undosys_step_encode;
562         ut->step_decode = image_undosys_step_decode;
563         ut->step_free = image_undosys_step_free;
564
565         ut->step_foreach_ID_ref = image_undosys_foreach_ID_ref;
566
567         ut->use_context = true;
568
569         ut->step_size = sizeof(ImageUndoStep);
570 }
571
572 /** \} */
573
574
575 /* -------------------------------------------------------------------- */
576 /** \name Utilities
577  * \{ */
578
579 ListBase *ED_image_undosys_step_get_tiles(UndoStep *us_p)
580 {
581         ImageUndoStep *us = (ImageUndoStep *)us_p;
582         return &us->tiles;
583 }
584
585 ListBase *ED_image_undo_get_tiles(void)
586 {
587         UndoStack *ustack = ED_undo_stack_get();
588         UndoStep *us_prev = ustack->step_init;
589         UndoStep *us_p = BKE_undosys_stack_init_or_active_with_type(ustack, BKE_UNDOSYS_TYPE_IMAGE);
590         ImageUndoStep *us = (ImageUndoStep *)us_p;
591         /* We should always have an undo push started when accessing tiles,
592          * not doing this means we won't have paint_mode correctly set. */
593         BLI_assert(us_p == us_prev);
594         if (us_p != us_prev) {
595                 /* Fallback value until we can be sure this never happens. */
596                 us->paint_mode = PAINT_MODE_TEXTURE_2D;
597         }
598         return ED_image_undosys_step_get_tiles(us_p);
599 }
600
601 /* restore painting image to previous state. Used for anchored and drag-dot style brushes*/
602 void ED_image_undo_restore(UndoStep *us)
603 {
604         ListBase *lb = ED_image_undosys_step_get_tiles(us);
605         image_undo_restore_runtime(lb);
606         image_undo_invalidate();
607 }
608
609 void ED_image_undo_push_begin(const char *name, int paint_mode)
610 {
611         UndoStack *ustack = ED_undo_stack_get();
612         bContext *C = NULL; /* special case, we never read from this. */
613         UndoStep *us_p = BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_IMAGE);
614         ImageUndoStep *us = (ImageUndoStep *)us_p;
615         BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D));
616         us->paint_mode = paint_mode;
617 }
618
619 void ED_image_undo_push_end(void)
620 {
621         UndoStack *ustack = ED_undo_stack_get();
622         BKE_undosys_step_push(ustack, NULL, NULL);
623 }
624
625 /** \} */