Sculpt: split generic part of image paint undo system into separate
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Wed, 4 Nov 2009 20:19:41 +0000 (20:19 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Wed, 4 Nov 2009 20:19:41 +0000 (20:19 +0000)
paint_undo.c file, to be reused for sculpt.

source/blender/editors/include/ED_sculpt.h
source/blender/editors/sculpt_paint/paint_image.c
source/blender/editors/sculpt_paint/paint_intern.h
source/blender/editors/sculpt_paint/paint_undo.c [new file with mode: 0644]
source/blender/editors/space_view3d/view3d_header.c
source/blender/editors/util/ed_util.c
source/blender/editors/util/undo.c

index 12ebd74b64bd4bb49ace7f4397e1cd59f663fd6b..085c8e894f84ad96c721231b6c0182ffee284dba 100644 (file)
@@ -45,8 +45,11 @@ void sculpt_get_redraw_planes(float planes[4][4], struct ARegion *ar,
 void ED_operatortypes_paint(void);
 void ED_keymap_paint(struct wmKeyConfig *keyconf);
 
 void ED_operatortypes_paint(void);
 void ED_keymap_paint(struct wmKeyConfig *keyconf);
 
-/* paint_image.c */
-void undo_imagepaint_step(int step);
-void undo_imagepaint_clear(void);
+/* paint_undo.c */
+#define UNDO_PAINT_IMAGE       0
+#define UNDO_PAINT_MESH                1
+
+void ED_undo_paint_step(struct bContext *C, int type, int step);
+void ED_undo_paint_free(void);
 
 #endif
 
 #endif
index 929f854242f7c36a2df9fc468d3e49b07f1e9944..d8c4d505fc9017a583dd4e3547d8d369b7d3dac2 100644 (file)
@@ -86,6 +86,7 @@
 #include "ED_image.h"
 #include "ED_object.h"
 #include "ED_screen.h"
 #include "ED_image.h"
 #include "ED_object.h"
 #include "ED_screen.h"
+#include "ED_sculpt.h"
 #include "ED_view3d.h"
 
 #include "WM_api.h"
 #include "ED_view3d.h"
 
 #include "WM_api.h"
 #define IMAPAINT_TILE_SIZE                     (1 << IMAPAINT_TILE_BITS)
 #define IMAPAINT_TILE_NUMBER(size)     (((size)+IMAPAINT_TILE_SIZE-1) >> IMAPAINT_TILE_BITS)
 
 #define IMAPAINT_TILE_SIZE                     (1 << IMAPAINT_TILE_BITS)
 #define IMAPAINT_TILE_NUMBER(size)     (((size)+IMAPAINT_TILE_SIZE-1) >> IMAPAINT_TILE_BITS)
 
-#define MAXUNDONAME    64
-
 static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint);
 
 
 static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint);
 
 
@@ -204,7 +203,7 @@ typedef struct ProjPaintImage {
        Image *ima;
        ImBuf *ibuf;
        ImagePaintPartialRedraw *partRedrawRect;
        Image *ima;
        ImBuf *ibuf;
        ImagePaintPartialRedraw *partRedrawRect;
-       struct UndoTile **undoRect; /* only used to build undo tiles after painting */
+       void **undoRect; /* only used to build undo tiles after painting */
        int touch;
 } ProjPaintImage;
 
        int touch;
 } ProjPaintImage;
 
@@ -332,32 +331,20 @@ typedef struct ProjPixelClone {
 
 /* Finish projection painting structs */
 
 
 /* Finish projection painting structs */
 
+typedef struct UndoImageTile {
+       struct UndoImageTile *next, *prev;
+
+       char idname[MAX_ID_NAME];       /* name instead of pointer*/
 
 
-typedef struct UndoTile {
-       struct UndoTile *next, *prev;
-       ID id;
        void *rect;
        int x, y;
        void *rect;
        int x, y;
-} UndoTile;
-
-typedef struct UndoElem {
-       struct UndoElem *next, *prev;
-       char name[MAXUNDONAME];
-       uintptr_t undosize;
+} UndoImageTile;
 
 
-       ImBuf *ibuf;
-       ListBase tiles;
-} UndoElem;
-
-static ListBase undobase = {NULL, NULL};
-static UndoElem *curundo = NULL;
 static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0};
 
 /* UNDO */
 
 static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0};
 
 /* UNDO */
 
-/* internal functions */
-
-static void undo_copy_tile(UndoTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int restore)
+static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int restore)
 {
        /* copy or swap contents of tile->rect and region in ibuf->rect */
        IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x*IMAPAINT_TILE_SIZE,
 {
        /* copy or swap contents of tile->rect and region in ibuf->rect */
        IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x*IMAPAINT_TILE_SIZE,
@@ -374,49 +361,52 @@ static void undo_copy_tile(UndoTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int rest
                        tile->y*IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
 }
 
                        tile->y*IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
 }
 
-static UndoTile *undo_init_tile(ID *id, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile)
+static void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile)
 {
 {
-       UndoTile *tile;
+       ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+       UndoImageTile *tile;
        int allocsize;
        int allocsize;
+
+       for(tile=lb->first; tile; tile=tile->next)
+               if(tile->x == x_tile && tile->y == y_tile && strcmp(tile->idname, ima->id.name)==0)
+                       return tile->rect;
        
        if (*tmpibuf==NULL)
                *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat|IB_rect, 0);
        
        
        if (*tmpibuf==NULL)
                *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat|IB_rect, 0);
        
-       tile= MEM_callocN(sizeof(UndoTile), "ImaUndoTile");
-       tile->id= *id;
+       tile= MEM_callocN(sizeof(UndoImageTile), "UndoImageTile");
+       strcpy(tile->idname, ima->id.name);
        tile->x= x_tile;
        tile->y= y_tile;
 
        allocsize= IMAPAINT_TILE_SIZE*IMAPAINT_TILE_SIZE*4;
        allocsize *= (ibuf->rect_float)? sizeof(float): sizeof(char);
        tile->x= x_tile;
        tile->y= y_tile;
 
        allocsize= IMAPAINT_TILE_SIZE*IMAPAINT_TILE_SIZE*4;
        allocsize *= (ibuf->rect_float)? sizeof(float): sizeof(char);
-       tile->rect= MEM_mapallocN(allocsize, "ImaUndoRect");
+       tile->rect= MEM_mapallocN(allocsize, "UndeImageTile.rect");
 
        undo_copy_tile(tile, *tmpibuf, ibuf, 0);
 
        undo_copy_tile(tile, *tmpibuf, ibuf, 0);
-       curundo->undosize += allocsize;
+       undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, allocsize);
 
 
-       BLI_addtail(&curundo->tiles, tile);
+       BLI_addtail(lb, tile);
        
        
-       return tile;
+       return tile->rect;
 }
 
 }
 
-static void undo_restore(UndoElem *undo)
+static void image_undo_restore(bContext *C, ListBase *lb)
 {
 {
+       Main *bmain= CTX_data_main(C);
        Image *ima = NULL;
        ImBuf *ibuf, *tmpibuf;
        Image *ima = NULL;
        ImBuf *ibuf, *tmpibuf;
-       UndoTile *tile;
-
-       if(!undo)
-               return;
+       UndoImageTile *tile;
 
        tmpibuf= IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32,
                                IB_rectfloat|IB_rect, 0);
        
 
        tmpibuf= IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32,
                                IB_rectfloat|IB_rect, 0);
        
-       for(tile=undo->tiles.first; tile; tile=tile->next) {
+       for(tile=lb->first; tile; tile=tile->next) {
                /* find image based on name, pointer becomes invalid with global undo */
                /* find image based on name, pointer becomes invalid with global undo */
-               if(ima && strcmp(tile->id.name, ima->id.name)==0);
+               if(ima && strcmp(tile->idname, ima->id.name)==0);
                else {
                else {
-                       for(ima=G.main->image.first; ima; ima=ima->id.next)
-                               if(strcmp(tile->id.name, ima->id.name)==0)
+                       for(ima=bmain->image.first; ima; ima=ima->id.next)
+                               if(strcmp(tile->idname, ima->id.name)==0)
                                        break;
                }
 
                                        break;
                }
 
@@ -435,117 +425,12 @@ static void undo_restore(UndoElem *undo)
        IMB_freeImBuf(tmpibuf);
 }
 
        IMB_freeImBuf(tmpibuf);
 }
 
-static void undo_free(UndoElem *undo)
+static void image_undo_free(ListBase *lb)
 {
 {
-       UndoTile *tile;
+       UndoImageTile *tile;
 
 
-       for(tile=undo->tiles.first; tile; tile=tile->next)
+       for(tile=lb->first; tile; tile=tile->next)
                MEM_freeN(tile->rect);
                MEM_freeN(tile->rect);
-       BLI_freelistN(&undo->tiles);
-}
-
-static void undo_imagepaint_push_begin(char *name)
-{
-       UndoElem *uel;
-       int nr;
-       
-       /* Undo push is split up in begin and end, the reason is that as painting
-        * happens more tiles are added to the list, and at the very end we know
-        * how much memory the undo used to remove old undo elements */
-
-       /* remove all undos after (also when curundo==NULL) */
-       while(undobase.last != curundo) {
-               uel= undobase.last;
-               undo_free(uel);
-               BLI_freelinkN(&undobase, uel);
-       }
-       
-       /* make new */
-       curundo= uel= MEM_callocN(sizeof(UndoElem), "undo file");
-       BLI_addtail(&undobase, uel);
-
-       /* name can be a dynamic string */
-       strncpy(uel->name, name, MAXUNDONAME-1);
-       
-       /* limit amount to the maximum amount*/
-       nr= 0;
-       uel= undobase.last;
-       while(uel) {
-               nr++;
-               if(nr==U.undosteps) break;
-               uel= uel->prev;
-       }
-       if(uel) {
-               while(undobase.first!=uel) {
-                       UndoElem *first= undobase.first;
-                       undo_free(first);
-                       BLI_freelinkN(&undobase, first);
-               }
-       }
-}
-
-static void undo_imagepaint_push_end()
-{
-       UndoElem *uel;
-       uintptr_t totmem, maxmem;
-
-       if(U.undomemory != 0) {
-               /* limit to maximum memory (afterwards, we can't know in advance) */
-               totmem= 0;
-               maxmem= ((uintptr_t)U.undomemory)*1024*1024;
-
-               uel= undobase.last;
-               while(uel) {
-                       totmem+= uel->undosize;
-                       if(totmem>maxmem) break;
-                       uel= uel->prev;
-               }
-
-               if(uel) {
-                       while(undobase.first!=uel) {
-                               UndoElem *first= undobase.first;
-                               undo_free(first);
-                               BLI_freelinkN(&undobase, first);
-                       }
-               }
-       }
-}
-
-void undo_imagepaint_step(int step)
-{
-       UndoElem *undo;
-
-       if(step==1) {
-               if(curundo==NULL);
-               else {
-                       if(G.f & G_DEBUG) printf("undo %s\n", curundo->name);
-                       undo_restore(curundo);
-                       curundo= curundo->prev;
-               }
-       }
-       else if(step==-1) {
-               if((curundo!=NULL && curundo->next==NULL) || undobase.first==NULL);
-               else {
-                       undo= (curundo && curundo->next)? curundo->next: undobase.first;
-                       undo_restore(undo);
-                       curundo= undo;
-                       if(G.f & G_DEBUG) printf("redo %s\n", undo->name);
-               }
-       }
-}
-
-void undo_imagepaint_clear(void)
-{
-       UndoElem *uel;
-       
-       uel= undobase.first;
-       while(uel) {
-               undo_free(uel);
-               uel= uel->next;
-       }
-
-       BLI_freelistN(&undobase);
-       curundo= NULL;
 }
 
 /* fast projection bucket array lookup, use the safe version for bound checking  */
 }
 
 /* fast projection bucket array lookup, use the safe version for bound checking  */
@@ -3316,7 +3201,7 @@ static void project_paint_end(ProjPaintState *ps)
                ProjPixel *projPixel;
                ImBuf *tmpibuf = NULL, *tmpibuf_float = NULL;
                LinkNode *pixel_node;
                ProjPixel *projPixel;
                ImBuf *tmpibuf = NULL, *tmpibuf_float = NULL;
                LinkNode *pixel_node;
-               UndoTile *tile;
+               void *tilerect;
                MemArena *arena = ps->arena_mt[0]; /* threaded arena re-used for non threaded case */
                                
                int bucket_tot = (ps->buckets_x * ps->buckets_y); /* we could get an X/Y but easier to loop through all possible buckets */
                MemArena *arena = ps->arena_mt[0]; /* threaded arena re-used for non threaded case */
                                
                int bucket_tot = (ps->buckets_x * ps->buckets_y); /* we could get an X/Y but easier to loop through all possible buckets */
@@ -3332,8 +3217,8 @@ static void project_paint_end(ProjPaintState *ps)
                int last_tile_width=0;
                
                for(a=0, last_projIma=ps->projImages; a < ps->image_tot; a++, last_projIma++) {
                int last_tile_width=0;
                
                for(a=0, last_projIma=ps->projImages; a < ps->image_tot; a++, last_projIma++) {
-                       int size = sizeof(UndoTile **) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->y);
-                       last_projIma->undoRect = (UndoTile **) BLI_memarena_alloc(arena, size);
+                       int size = sizeof(void **) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->y);
+                       last_projIma->undoRect = (void **) BLI_memarena_alloc(arena, size);
                        memset(last_projIma->undoRect, 0, size);
                        last_projIma->ibuf->userflags |= IB_BITMAPDIRTY;
                }
                        memset(last_projIma->undoRect, 0, size);
                        last_projIma->ibuf->userflags |= IB_BITMAPDIRTY;
                }
@@ -3373,21 +3258,21 @@ static void project_paint_end(ProjPaintState *ps)
                                        
                                        if (last_projIma->undoRect[tile_index]==NULL) {
                                                /* add the undo tile from the modified image, then write the original colors back into it */
                                        
                                        if (last_projIma->undoRect[tile_index]==NULL) {
                                                /* add the undo tile from the modified image, then write the original colors back into it */
-                                               tile = last_projIma->undoRect[tile_index] = undo_init_tile(&last_projIma->ima->id, last_projIma->ibuf, is_float ? (&tmpibuf_float):(&tmpibuf) , x_tile, y_tile);
+                                               tilerect = last_projIma->undoRect[tile_index] = image_undo_push_tile(last_projIma->ima, last_projIma->ibuf, is_float ? (&tmpibuf_float):(&tmpibuf) , x_tile, y_tile);
                                        }
                                        else {
                                        }
                                        else {
-                                               tile = last_projIma->undoRect[tile_index];
+                                               tilerect = last_projIma->undoRect[tile_index];
                                        }
                                        
                                        /* This is a BIT ODD, but overwrite the undo tiles image info with this pixels original color
                                         * because allocating the tiles allong the way slows down painting */
                                        
                                        if (is_float) {
                                        }
                                        
                                        /* This is a BIT ODD, but overwrite the undo tiles image info with this pixels original color
                                         * because allocating the tiles allong the way slows down painting */
                                        
                                        if (is_float) {
-                                               float *rgba_fp = (float *)tile->rect + (((projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE)) * 4;
+                                               float *rgba_fp = (float *)tilerect + (((projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE)) * 4;
                                                QUATCOPY(rgba_fp, projPixel->origColor.f);
                                        }
                                        else {
                                                QUATCOPY(rgba_fp, projPixel->origColor.f);
                                        }
                                        else {
-                                               ((unsigned int *)tile->rect)[ (projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE ] = projPixel->origColor.uint;
+                                               ((unsigned int *)tilerect)[ (projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE ] = projPixel->origColor.uint;
                                        }
                                }
                        }
                                        }
                                }
                        }
@@ -3958,7 +3843,6 @@ static void imapaint_clear_partial_redraw()
 static void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h)
 {
        ImBuf *tmpibuf = NULL;
 static void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h)
 {
        ImBuf *tmpibuf = NULL;
-       UndoTile *tile;
        int srcx= 0, srcy= 0, origx;
 
        IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h);
        int srcx= 0, srcy= 0, origx;
 
        IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h);
@@ -3985,17 +3869,9 @@ static void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w,
        origx = (x >> IMAPAINT_TILE_BITS);
        y = (y >> IMAPAINT_TILE_BITS);
        
        origx = (x >> IMAPAINT_TILE_BITS);
        y = (y >> IMAPAINT_TILE_BITS);
        
-       for (; y <= h; y++) {
-               for (x=origx; x <= w; x++) {
-                       for(tile=curundo->tiles.first; tile; tile=tile->next)
-                               if(tile->x == x && tile->y == y && strcmp(tile->id.name, ima->id.name)==0)
-                                       break;
-
-                       if(!tile) {
-                               undo_init_tile(&ima->id, ibuf, &tmpibuf, x, y);
-                       }
-               }
-       }
+       for (; y <= h; y++)
+               for (x=origx; x <= w; x++)
+                       image_undo_push_tile(ima, ibuf, &tmpibuf, x, y);
 
        ibuf->userflags |= IB_BITMAPDIRTY;
        
 
        ibuf->userflags |= IB_BITMAPDIRTY;
        
@@ -4593,7 +4469,8 @@ static int texture_paint_init(bContext *C, wmOperator *op)
        }
        
        settings->imapaint.flag |= IMAGEPAINT_DRAWING;
        }
        
        settings->imapaint.flag |= IMAGEPAINT_DRAWING;
-       undo_imagepaint_push_begin("Image Paint");
+       undo_paint_push_begin(UNDO_PAINT_IMAGE, "Image Paint",
+               image_undo_restore, image_undo_free);
 
        /* create painter */
        pop->painter= brush_painter_new(pop->s.brush);
 
        /* create painter */
        pop->painter= brush_painter_new(pop->s.brush);
@@ -4657,7 +4534,7 @@ static void paint_exit(bContext *C, wmOperator *op)
        }
        
        paint_redraw(C, &pop->s, 1);
        }
        
        paint_redraw(C, &pop->s, 1);
-       undo_imagepaint_push_end();
+       undo_paint_push_end(UNDO_PAINT_IMAGE);
        
        if(pop->s.warnmultifile)
                BKE_reportf(op->reports, RPT_WARNING, "Image requires 4 color channels to paint: %s", pop->s.warnmultifile);
        
        if(pop->s.warnmultifile)
                BKE_reportf(op->reports, RPT_WARNING, "Image requires 4 color channels to paint: %s", pop->s.warnmultifile);
@@ -5256,3 +5133,4 @@ int facemask_paint_poll(bContext *C)
 {
        return paint_facesel_test(CTX_data_active_object(C));
 }
 {
        return paint_facesel_test(CTX_data_active_object(C));
 }
+
index 0689e8e63d7d10004e04dfddc48189179a0c8766..46f073243e55eacd8853f8c1cebf1539e0be7038 100644 (file)
@@ -41,6 +41,7 @@ struct wmOperator;
 struct wmOperatorType;
 struct ARegion;
 struct VPaint;
 struct wmOperatorType;
 struct ARegion;
 struct VPaint;
+struct ListBase;
 
 /* paint_stroke.c */
 typedef int (*StrokeGetLocation)(struct bContext *C, struct PaintStroke *stroke, float location[3], float mouse[2]);
 
 /* paint_stroke.c */
 typedef int (*StrokeGetLocation)(struct bContext *C, struct PaintStroke *stroke, float location[3], float mouse[2]);
@@ -102,5 +103,14 @@ void PAINT_OT_face_deselect_all(struct wmOperatorType *ot);
 
 int facemask_paint_poll(struct bContext *C);
 
 
 int facemask_paint_poll(struct bContext *C);
 
+/* paint_undo.c */
+typedef void (*UndoRestoreCb)(struct bContext *C, struct ListBase *lb);
+typedef void (*UndoFreeCb)(struct ListBase *lb);
+
+void undo_paint_push_begin(int type, char *name, UndoRestoreCb restore, UndoFreeCb free);
+struct ListBase *undo_paint_push_get_list(int type);
+void undo_paint_push_count_alloc(int type, int size);
+void undo_paint_push_end(int type);
+
 #endif /* ED_PAINT_INTERN_H */
 
 #endif /* ED_PAINT_INTERN_H */
 
diff --git a/source/blender/editors/sculpt_paint/paint_undo.c b/source/blender/editors/sculpt_paint/paint_undo.c
new file mode 100644 (file)
index 0000000..9bc6cac
--- /dev/null
@@ -0,0 +1,231 @@
+/**
+ * $Id$
+ *
+ * Undo system for painting and sculpting.
+ * 
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA       02111-1307, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_userdef_types.h"
+
+#include "BLI_listbase.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+
+#include "ED_sculpt.h"
+
+#include "paint_intern.h"
+
+#define MAXUNDONAME    64
+
+typedef struct UndoElem {
+       struct UndoElem *next, *prev;
+       char name[MAXUNDONAME];
+       uintptr_t undosize;
+
+       ListBase elems;
+
+       UndoRestoreCb restore;
+       UndoFreeCb free;
+} UndoElem;
+
+typedef struct UndoStack {
+       int type;
+       ListBase elems;
+       UndoElem *current;
+} UndoStack;
+
+static UndoStack ImageUndoStack = {UNDO_PAINT_IMAGE, {NULL, NULL}, NULL};
+static UndoStack MeshUndoStack = {UNDO_PAINT_MESH, {NULL, NULL}, NULL};
+
+/* Generic */
+
+static void undo_restore(bContext *C, UndoStack *stack, UndoElem *uel)
+{
+       if(uel && uel->restore)
+               uel->restore(C, &uel->elems);
+}
+
+static void undo_elem_free(UndoStack *stack, UndoElem *uel)
+{
+       if(uel && uel->free) {
+               uel->free(&uel->elems);
+               BLI_freelistN(&uel->elems);
+       }
+}
+
+static void undo_stack_push_begin(UndoStack *stack, char *name, UndoRestoreCb restore, UndoFreeCb free)
+{
+       UndoElem *uel;
+       int nr;
+       
+       /* Undo push is split up in begin and end, the reason is that as painting
+        * happens more tiles/nodes are added to the list, and at the very end we
+        * know how much memory the undo used to remove old undo elements */
+
+       /* remove all undos after (also when stack->current==NULL) */
+       while(stack->elems.last != stack->current) {
+               uel= stack->elems.last;
+               undo_elem_free(stack, uel);
+               BLI_freelinkN(&stack->elems, uel);
+       }
+       
+       /* make new */
+       stack->current= uel= MEM_callocN(sizeof(UndoElem), "undo file");
+       uel->restore= restore;
+       uel->free= free;
+       BLI_addtail(&stack->elems, uel);
+
+       /* name can be a dynamic string */
+       strncpy(uel->name, name, MAXUNDONAME-1);
+       
+       /* limit amount to the maximum amount*/
+       nr= 0;
+       uel= stack->elems.last;
+       while(uel) {
+               nr++;
+               if(nr==U.undosteps) break;
+               uel= uel->prev;
+       }
+       if(uel) {
+               while(stack->elems.first!=uel) {
+                       UndoElem *first= stack->elems.first;
+                       undo_elem_free(stack, first);
+                       BLI_freelinkN(&stack->elems, first);
+               }
+       }
+}
+
+static void undo_stack_push_end(UndoStack *stack)
+{
+       UndoElem *uel;
+       uintptr_t totmem, maxmem;
+
+       if(U.undomemory != 0) {
+               /* limit to maximum memory (afterwards, we can't know in advance) */
+               totmem= 0;
+               maxmem= ((uintptr_t)U.undomemory)*1024*1024;
+
+               uel= stack->elems.last;
+               while(uel) {
+                       totmem+= uel->undosize;
+                       if(totmem>maxmem) break;
+                       uel= uel->prev;
+               }
+
+               if(uel) {
+                       while(stack->elems.first!=uel) {
+                               UndoElem *first= stack->elems.first;
+                               undo_elem_free(stack, first);
+                               BLI_freelinkN(&stack->elems, first);
+                       }
+               }
+       }
+}
+
+static void undo_stack_step(bContext *C, UndoStack *stack, int step)
+{
+       UndoElem *undo;
+
+       if(step==1) {
+               if(stack->current==NULL);
+               else {
+                       if(G.f & G_DEBUG) printf("undo %s\n", stack->current->name);
+                       undo_restore(C, stack, stack->current);
+                       stack->current= stack->current->prev;
+               }
+       }
+       else if(step==-1) {
+               if((stack->current!=NULL && stack->current->next==NULL) || stack->elems.first==NULL);
+               else {
+                       undo= (stack->current && stack->current->next)? stack->current->next: stack->elems.first;
+                       undo_restore(C, stack, undo);
+                       stack->current= undo;
+                       if(G.f & G_DEBUG) printf("redo %s\n", undo->name);
+               }
+       }
+}
+
+static void undo_stack_free(UndoStack *stack)
+{
+       UndoElem *uel;
+       
+       for(uel=stack->elems.first; uel; uel=uel->next)
+               undo_elem_free(stack, uel);
+
+       BLI_freelistN(&stack->elems);
+       stack->current= NULL;
+}
+
+/* Exported Functions */
+
+void undo_paint_push_begin(int type, char *name, UndoRestoreCb restore, UndoFreeCb free)
+{
+       if(type == UNDO_PAINT_IMAGE)
+               undo_stack_push_begin(&ImageUndoStack, name, restore, free);
+       else if(type == UNDO_PAINT_MESH)
+               undo_stack_push_begin(&MeshUndoStack, name, restore, free);
+}
+
+ListBase *undo_paint_push_get_list(int type)
+{
+       if(type == UNDO_PAINT_IMAGE)
+               return &ImageUndoStack.current->elems;
+       else if(type == UNDO_PAINT_MESH)
+               return &MeshUndoStack.current->elems;
+       
+       return NULL;
+}
+
+void undo_paint_push_count_alloc(int type, int size)
+{
+       if(type == UNDO_PAINT_IMAGE)
+               ImageUndoStack.current->undosize += size;
+       else if(type == UNDO_PAINT_MESH)
+               MeshUndoStack.current->undosize += size;
+}
+
+void undo_paint_push_end(int type)
+{
+       if(type == UNDO_PAINT_IMAGE)
+               undo_stack_push_end(&ImageUndoStack);
+       else if(type == UNDO_PAINT_MESH)
+               undo_stack_push_end(&MeshUndoStack);
+}
+
+void ED_undo_paint_step(bContext *C, int type, int step)
+{
+       if(type == UNDO_PAINT_IMAGE)
+               undo_stack_step(C, &ImageUndoStack, step);
+       else if(type == UNDO_PAINT_MESH)
+               undo_stack_step(C, &MeshUndoStack, step);
+}
+
+void ED_undo_paint_free(void)
+{
+       undo_stack_free(&ImageUndoStack);
+       undo_stack_free(&MeshUndoStack);
+}
+
index 9b1b239be70a21c47e4dd03845df9bdf3d4ef203..a953afde0d523b4a27f7006a9f49be35d2891945 100644 (file)
@@ -1411,7 +1411,7 @@ static void do_view3d_tpaintmenu(bContext *C, void *arg, int event)
 #if 0
        switch(event) {
        case 0: /* undo image painting */
 #if 0
        switch(event) {
        case 0: /* undo image painting */
-               undo_imagepaint_step(1);
+               ED_paint_undo_step(UNDO_PAINT_IMAGE, 1);
                break;
        }
 
                break;
        }
 
index ae1e932bb81d9ae6a2bc810659bac7fda1f429e4..fc2576eef5d687c27584e89f45bd9da9022808b6 100644 (file)
@@ -60,7 +60,7 @@ void ED_editors_exit(bContext *C)
        
        /* frees all editmode undos */
        undo_editmode_clear();
        
        /* frees all editmode undos */
        undo_editmode_clear();
-       undo_imagepaint_clear();
+       ED_undo_paint_free();
        
        for(sce=G.main->scene.first; sce; sce= sce->id.next) {
                if(sce->obedit) {
        
        for(sce=G.main->scene.first; sce; sce= sce->id.next) {
                if(sce->obedit) {
index d26f7a7a4847250d8d28f948ccbc90c65aadafbf..18e3304c1910a48e08da37156a630ce2d1d4c382 100644 (file)
@@ -124,7 +124,7 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
                SpaceImage *sima= (SpaceImage *)sa->spacedata.first;
                
                if((obact && obact->mode & OB_MODE_TEXTURE_PAINT) || sima->flag & SI_DRAWTOOL) {
                SpaceImage *sima= (SpaceImage *)sa->spacedata.first;
                
                if((obact && obact->mode & OB_MODE_TEXTURE_PAINT) || sima->flag & SI_DRAWTOOL) {
-                       undo_imagepaint_step(step);
+                       ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step);
 
                        WM_event_add_notifier(C, NC_WINDOW, NULL);
                        return OPERATOR_FINISHED;
 
                        WM_event_add_notifier(C, NC_WINDOW, NULL);
                        return OPERATOR_FINISHED;
@@ -146,7 +146,7 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
                int do_glob_undo= 0;
                
                if(obact && obact->mode & OB_MODE_TEXTURE_PAINT)
                int do_glob_undo= 0;
                
                if(obact && obact->mode & OB_MODE_TEXTURE_PAINT)
-                       undo_imagepaint_step(step);
+                       ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step);
                else if(obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
                        if(step==1)
                                PE_undo(CTX_data_scene(C));
                else if(obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
                        if(step==1)
                                PE_undo(CTX_data_scene(C));