diff options
Diffstat (limited to 'source/blender/src/imagepaint.c')
-rw-r--r-- | source/blender/src/imagepaint.c | 303 |
1 files changed, 82 insertions, 221 deletions
diff --git a/source/blender/src/imagepaint.c b/source/blender/src/imagepaint.c index 164c368b6fa..15c289cc21c 100644 --- a/source/blender/src/imagepaint.c +++ b/source/blender/src/imagepaint.c @@ -44,8 +44,6 @@ #include "BLI_winstuff.h" #endif #include "BLI_arithb.h" -#include "BLI_blenlib.h" -#include "BLI_dynstr.h" #include "PIL_time.h" #include "IMB_imbuf.h" @@ -66,12 +64,10 @@ #include "BKE_brush.h" #include "BKE_global.h" #include "BKE_image.h" -#include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_node.h" #include "BKE_utildefines.h" -#include "BIF_interface.h" #include "BIF_mywindow.h" #include "BIF_screen.h" #include "BIF_space.h" @@ -82,11 +78,10 @@ #include "BSE_trans_types.h" #include "BSE_view.h" +#include "BDR_drawmesh.h" #include "BDR_imagepaint.h" #include "BDR_vpaint.h" -#include "GPU_draw.h" - #include "GHOST_Types.h" #include "blendef.h" @@ -108,8 +103,6 @@ #define IMAPAINT_TILE_SIZE (1 << IMAPAINT_TILE_BITS) #define IMAPAINT_TILE_NUMBER(size) (((size)+IMAPAINT_TILE_SIZE-1) >> IMAPAINT_TILE_BITS) -#define MAXUNDONAME 64 - typedef struct ImagePaintState { Brush *brush; short tool, blend; @@ -127,206 +120,48 @@ typedef struct ImagePaintState { float uv[2]; } ImagePaintState; -typedef struct UndoTile { - struct UndoTile *next, *prev; - ID id; - void *rect; - int x, y; -} UndoTile; - -typedef struct UndoElem { - struct UndoElem *next, *prev; - char name[MAXUNDONAME]; - unsigned long undosize; - - ImBuf *ibuf; - ListBase tiles; -} UndoElem; +typedef struct ImagePaintUndo { + Image *image; + ImBuf *tilebuf; + void **tiles; + int xtiles, ytiles; +} ImagePaintUndo; typedef struct ImagePaintPartialRedraw { int x1, y1, x2, y2; int enabled; } ImagePaintPartialRedraw; -static ListBase undobase = {NULL, NULL}; -static UndoElem *curundo = NULL; +static ImagePaintUndo imapaintundo = {NULL, NULL, NULL, 0, 0}; static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0}; -/* UNDO */ - -/* internal functions */ - -static void undo_copy_tile(UndoTile *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, - tile->y*IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE); - - if(ibuf->rect_float) SWAP(void*, tmpibuf->rect_float, tile->rect) - else SWAP(void*, tmpibuf->rect, tile->rect) - - if(restore) - IMB_rectcpy(ibuf, tmpibuf, tile->x*IMAPAINT_TILE_SIZE, - tile->y*IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE); -} - -static void undo_restore(UndoElem *undo) +static void init_imagapaint_undo(Image *ima, ImBuf *ibuf) { - Image *ima = NULL; - ImBuf *ibuf, *tmpibuf; - UndoTile *tile; - - if(!undo) - return; - - tmpibuf= IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, - IB_rectfloat|IB_rect, 0); - - for(tile=undo->tiles.first; tile; tile=tile->next) { - /* find image based on name, pointer becomes invalid with global undo */ - if(ima && strcmp(tile->id.name, ima->id.name)==0); - else { - for(ima=G.main->image.first; ima; ima=ima->id.next) - if(strcmp(tile->id.name, ima->id.name)==0) - break; - } - - ibuf= BKE_image_get_ibuf(ima, NULL); - - if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) - continue; - - undo_copy_tile(tile, tmpibuf, ibuf, 1); - - GPU_free_image(ima); /* force OpenGL reload */ - if(ibuf->rect_float) - imb_freerectImBuf(ibuf); /* force recreate of char rect */ - } - - IMB_freeImBuf(tmpibuf); -} - -static void undo_free(UndoElem *undo) -{ - UndoTile *tile; - - for(tile=undo->tiles.first; tile; tile=tile->next) - 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; - unsigned long totmem, maxmem; - - if(U.undomemory != 0) { - /* limit to maximum memory (afterwards, we can't know in advance) */ - totmem= 0; - maxmem= ((unsigned long)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); - } - } - } + int xt, yt; + + imapaintundo.image = ima; + imapaintundo.xtiles = xt = IMAPAINT_TILE_NUMBER(ibuf->x); + imapaintundo.ytiles = yt = IMAPAINT_TILE_NUMBER(ibuf->y); + imapaintundo.tiles = MEM_callocN(sizeof(void*)*xt*yt, "ImagePaintUndoTiles"); + imapaintundo.tilebuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, + ibuf->depth, (ibuf->rect_float)? IB_rectfloat: IB_rect, 0); } -/* external functions */ - -/* 1= an undo, -1 is a redo. */ -void undo_imagepaint_step(int step) +static void imapaint_copy_tile(ImBuf *ibuf, int tile, int x, int y, int swapundo) { - UndoElem *undo; - - if(step==1) { - if(curundo==NULL) error("No more steps to undo"); - 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) error("No more steps to redo"); - 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); - } - } - - allqueue(REDRAWVIEW3D, 0); - allqueue(REDRAWIMAGE, 0); -} + IMB_rectcpy(imapaintundo.tilebuf, ibuf, 0, 0, x*IMAPAINT_TILE_SIZE, + y*IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE); -void undo_imagepaint_clear(void) -{ - UndoElem *uel; + if (imapaintundo.tilebuf->rect_float) + SWAP(void*, imapaintundo.tilebuf->rect_float, imapaintundo.tiles[tile]) + else + SWAP(void*, imapaintundo.tilebuf->rect, imapaintundo.tiles[tile]) - uel= undobase.first; - while(uel) { - undo_free(uel); - uel= uel->next; - } - - BLI_freelistN(&undobase); - curundo= NULL; + if (swapundo) + IMB_rectcpy(ibuf, imapaintundo.tilebuf, x*IMAPAINT_TILE_SIZE, + y*IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE); } -/* Imagepaint Partial Redraw & Dirty Region */ - static void imapaint_clear_partial_redraw() { memset(&imapaintpartial, 0, sizeof(imapaintpartial)); @@ -334,9 +169,7 @@ 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; - UndoTile *tile; - int srcx= 0, srcy= 0, origx, allocsize; + int srcx= 0, srcy= 0, origx, tile, allocsize; IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h); @@ -362,36 +195,24 @@ 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); - tmpibuf= IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, - IB_rectfloat|IB_rect, 0); - 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) { - tile= MEM_callocN(sizeof(UndoTile), "ImaUndoTile"); - tile->id= ima->id; - tile->x= x; - tile->y= y; - - allocsize= IMAPAINT_TILE_SIZE*IMAPAINT_TILE_SIZE*4; - allocsize *= (ibuf->rect_float)? sizeof(float): sizeof(char); - tile->rect= MEM_mapallocN(allocsize, "ImaUndoRect"); - - undo_copy_tile(tile, tmpibuf, ibuf, 0); - curundo->undosize += allocsize; + if (ima != imapaintundo.image) { + free_imagepaint(); + init_imagapaint_undo(ima, ibuf); + } - BLI_addtail(&curundo->tiles, tile); + tile = y*imapaintundo.xtiles + x; + if (!imapaintundo.tiles[tile]) { + allocsize= (ibuf->rect_float)? sizeof(float): sizeof(char); + imapaintundo.tiles[tile]= MEM_mapallocN(allocsize*4* + IMAPAINT_TILE_SIZE*IMAPAINT_TILE_SIZE, "ImagePaintUndoTile"); + imapaint_copy_tile(ibuf, tile, x, y, 0); } } } ibuf->userflags |= IB_BITMAPDIRTY; - - IMB_freeImBuf(tmpibuf); } static void imapaint_image_update(Image *image, ImBuf *ibuf, short texpaint) @@ -405,7 +226,7 @@ static void imapaint_image_update(Image *image, ImBuf *ibuf, short texpaint) if(texpaint || G.sima->lock) { int w = imapaintpartial.x2 - imapaintpartial.x1; int h = imapaintpartial.y2 - imapaintpartial.y1; - GPU_paint_update_image(image, imapaintpartial.x1, imapaintpartial.y1, w, h); + update_realtime_image(image, imapaintpartial.x1, imapaintpartial.y1, w, h); } } @@ -418,7 +239,7 @@ static void imapaint_redraw(int final, int texpaint, Image *image) allqueue(REDRAWIMAGE, 0); else if(!G.sima->lock) { if(image) - GPU_free_image(image); /* force OpenGL reload */ + free_realtime_image(image); /* force OpenGL reload */ allqueue(REDRAWVIEW3D, 0); } allqueue(REDRAWHEADERS, 0); @@ -448,6 +269,46 @@ static void imapaint_redraw(int final, int texpaint, Image *image) force_draw(0); } +void imagepaint_undo() +{ + Image *ima= imapaintundo.image; + ImBuf *ibuf= BKE_image_get_ibuf(ima, G.sima?&G.sima->iuser:NULL); + int x, y, tile; + + if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) + return; + + for (tile = 0, y = 0; y < imapaintundo.ytiles; y++) + for (x = 0; x < imapaintundo.xtiles; x++, tile++) + if (imapaintundo.tiles[tile]) + imapaint_copy_tile(ibuf, tile, x, y, 1); + + free_realtime_image(ima); /* force OpenGL reload */ + if(ibuf->rect_float) + imb_freerectImBuf(ibuf); /* force recreate of char rect */ + + allqueue(REDRAWIMAGE, 0); + allqueue(REDRAWVIEW3D, 0); +} + +void free_imagepaint() +{ + /* todo: does this need to be in the same places as editmode_undo_clear, + vertex paint isn't? */ + int i, size = imapaintundo.xtiles*imapaintundo.ytiles; + + if (imapaintundo.tiles) { + for (i = 0; i < size; i++) + if (imapaintundo.tiles[i]) + MEM_freeN(imapaintundo.tiles[i]); + MEM_freeN(imapaintundo.tiles); + } + if (imapaintundo.tilebuf) + IMB_freeImBuf(imapaintundo.tilebuf); + + memset(&imapaintundo, 0, sizeof(imapaintundo)); +} + /* Image Paint Operations */ static void imapaint_ibuf_get_set_rgb(ImBuf *ibuf, int x, int y, short torus, short set, float *rgb) @@ -719,6 +580,7 @@ static void imapaint_paint_stroke(ImagePaintState *s, BrushPainter *painter, sho int breakstroke = 0, redraw = 0; if (texpaint) { + /* pick new face and image */ if (facesel_face_pick(s->me, mval, &newfaceindex, 0)) { ImBuf *ibuf; @@ -830,7 +692,7 @@ void imagepaint_paint(short mousebutton, short texpaint) } settings->imapaint.flag |= IMAGEPAINT_DRAWING; - undo_imagepaint_push_begin("Image Paint"); + free_imagepaint(); /* create painter and paint once */ painter= brush_painter_new(s.brush); @@ -879,7 +741,6 @@ void imagepaint_paint(short mousebutton, short texpaint) brush_painter_free(painter); imapaint_redraw(1, texpaint, s.image); - undo_imagepaint_push_end(); if (texpaint) { if (s.warnmultifile) |