7ec7dd20dc58e06401734c9693b62135656e5cf2
[blender.git] / source / blender / editors / sculpt_paint / paint_image_undo.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * along with this program; if not, write to the Free Software Foundation,
15  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16  *
17  * ***** END GPL LICENSE BLOCK *****
18  */
19
20 /** \file blender/editors/sculpt_paint/paint_image_undo.c
21  *  \ingroup edsculpt
22  */
23
24 #include "MEM_guardedalloc.h"
25
26 #include "BLI_math.h"
27 #include "BLI_blenlib.h"
28 #include "BLI_utildefines.h"
29 #include "BLI_threads.h"
30
31 #include "DNA_image_types.h"
32 #include "DNA_windowmanager_types.h"
33 #include "DNA_object_types.h"
34 #include "DNA_screen_types.h"
35 #include "DNA_space_types.h"
36
37 #include "IMB_imbuf.h"
38 #include "IMB_imbuf_types.h"
39
40 #include "BKE_context.h"
41 #include "BKE_depsgraph.h"
42 #include "BKE_image.h"
43 #include "BKE_main.h"
44 #include "BKE_undo_system.h"
45
46 #include "ED_paint.h"
47 #include "ED_undo.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                 DAG_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         UndoImageTile *tile;
348
349         for (tile = lb->first; tile; tile = tile->next) {
350                 MEM_freeN(tile->rect.pt);
351         }
352 }
353
354 void ED_image_undo_push_begin(const char *name)
355 {
356         UndoStack *ustack = ED_undo_stack_get();
357         bContext *C = NULL; /* special case, we never read from this. */
358         BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_IMAGE);
359 }
360
361 void ED_image_undo_push_end(void)
362 {
363         UndoStack *ustack = ED_undo_stack_get();
364         BKE_undosys_step_push(ustack, NULL, NULL);
365 }
366
367 static void image_undo_invalidate(void)
368 {
369         UndoImageTile *tile;
370         ListBase *lb = ED_image_undo_get_tiles();
371
372         for (tile = lb->first; tile; tile = tile->next) {
373                 tile->valid = false;
374         }
375 }
376
377 /** \} */
378
379 /* -------------------------------------------------------------------- */
380 /** \name Implements ED Undo System
381  * \{ */
382
383 typedef struct ImageUndoStep {
384         UndoStep step;
385         ListBase tiles;
386
387         /* Use for all ID lookups (can be NULL). */
388         struct UndoIDPtrMap *id_map;
389 } ImageUndoStep;
390
391 static void image_undosys_step_encode_store_ids(ImageUndoStep *us)
392 {
393         us->id_map = BKE_undosys_ID_map_create();
394
395         ID *image_prev = NULL;
396         for (UndoImageTile *tile = us->tiles.first; tile; tile = tile->next) {
397                 BKE_undosys_ID_map_add_with_prev(us->id_map, &tile->ima->id, &image_prev);
398         }
399 }
400
401 /* Restore at runtime. */
402 #if 0
403 static void paint_undosys_step_decode_restore_ids(ImageUndoStep *us)
404 {
405         ID *image_prev[2] = {NULL};
406         for (UndoImageTile *tile = us->tiles.first; tile; tile = tile->next) {
407                 tile->ima = (Image *)BKE_undosys_ID_map_lookup_with_prev(us->id_map, &tile->ima->id, image_prev);
408         }
409 }
410 #endif
411
412 static bool image_undosys_poll(bContext *C)
413 {
414         Object *obact = CTX_data_active_object(C);
415
416         ScrArea *sa = CTX_wm_area(C);
417         if (sa && (sa->spacetype == SPACE_IMAGE)) {
418                 SpaceImage *sima = (SpaceImage *)sa->spacedata.first;
419                 if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) {
420                         return true;
421                 }
422         }
423         else if (sa && (sa->spacetype == SPACE_VIEW3D)) {
424                 if (obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) {
425                         return true;
426                 }
427         }
428         return false;
429 }
430
431 static void image_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p)
432 {
433         ImageUndoStep *us = (ImageUndoStep *)us_p;
434         /* dummy, memory is cleared anyway. */
435         BLI_listbase_clear(&us->tiles);
436 }
437
438 static bool image_undosys_step_encode(struct bContext *UNUSED(C), UndoStep *us_p)
439 {
440         /* dummy, encoding is done along the way by adding tiles
441          * to the current 'ImageUndoStep' added by encode_init. */
442         ImageUndoStep *us = (ImageUndoStep *)us_p;
443
444         BLI_assert(us->step.data_size == 0);
445
446         int allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
447
448
449         /* first dispose of invalid tiles (may happen due to drag dot for instance) */
450         for (UndoImageTile *tile = us->tiles.first; tile;) {
451                 if (!tile->valid) {
452                         UndoImageTile *tmp_tile = tile->next;
453                         MEM_freeN(tile->rect.pt);
454                         BLI_freelinkN(&us->tiles, tile);
455                         tile = tmp_tile;
456                 }
457                 else {
458                         us->step.data_size += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char));
459                         tile = tile->next;
460                 }
461         }
462
463         image_undosys_step_encode_store_ids(us);
464
465         return true;
466 }
467
468 static void image_undosys_step_decode(struct bContext *UNUSED(C), UndoStep *us_p, int UNUSED(dir))
469 {
470         ImageUndoStep *us = (ImageUndoStep *)us_p;
471 #if 0
472         paint_undosys_step_decode_restore_ids(us);
473 #endif
474         image_undo_restore_list(&us->tiles, us->id_map);
475 }
476
477 static void image_undosys_step_free(UndoStep *us_p)
478 {
479         ImageUndoStep *us = (ImageUndoStep *)us_p;
480         image_undo_free_list(&us->tiles);
481         BKE_undosys_ID_map_destroy(us->id_map);
482 }
483
484 static void image_undosys_foreach_ID_ref(
485         UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
486 {
487         ImageUndoStep *us = (ImageUndoStep *)us_p;
488         if (us->id_map != NULL) {
489                 BKE_undosys_ID_map_foreach_ID_ref(us->id_map, foreach_ID_ref_fn, user_data);
490         }
491 }
492
493 /* Export for ED_undo_sys. */
494 void ED_image_undosys_type(UndoType *ut)
495 {
496         ut->name = "Image";
497         ut->poll = image_undosys_poll;
498         ut->step_encode_init = image_undosys_step_encode_init;
499         ut->step_encode = image_undosys_step_encode;
500         ut->step_decode = image_undosys_step_decode;
501         ut->step_free = image_undosys_step_free;
502
503         ut->step_foreach_ID_ref = image_undosys_foreach_ID_ref;
504
505         ut->mode = BKE_UNDOTYPE_MODE_ACCUMULATE;
506         ut->use_context = true;
507
508         ut->step_size = sizeof(ImageUndoStep);
509 }
510
511 /** \} */
512
513
514 /* -------------------------------------------------------------------- */
515 /** \name Utilities
516  * \{ */
517
518 ListBase *ED_image_undosys_step_get_tiles(UndoStep *us_p)
519 {
520         ImageUndoStep *us = (ImageUndoStep *)us_p;
521         return &us->tiles;
522 }
523
524 ListBase *ED_image_undo_get_tiles(void)
525 {
526         UndoStack *ustack = ED_undo_stack_get();
527         UndoStep *us = BKE_undosys_stack_init_or_active_with_type(ustack, BKE_UNDOSYS_TYPE_IMAGE);
528         return ED_image_undosys_step_get_tiles(us);
529 }
530
531 /* restore painting image to previous state. Used for anchored and drag-dot style brushes*/
532 void ED_image_undo_restore(UndoStep *us)
533 {
534         ListBase *lb = ED_image_undosys_step_get_tiles(us);
535         image_undo_restore_runtime(lb);
536         image_undo_invalidate();
537 }
538
539 /** \} */