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