diff options
Diffstat (limited to 'source/blender/editors/sculpt_paint/paint_image.c')
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_image.c | 412 |
1 files changed, 52 insertions, 360 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index bf344e1f721..cb6dba4772f 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -39,7 +39,6 @@ #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" -#include "BLI_threads.h" #include "BLT_translation.h" @@ -50,16 +49,17 @@ #include "DNA_node_types.h" #include "DNA_object_types.h" +#include "BKE_colorband.h" #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_DerivedMesh.h" #include "BKE_brush.h" -#include "BKE_image.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_node.h" #include "BKE_paint.h" -#include "BKE_texture.h" +#include "BKE_undo_system.h" + #include "UI_interface.h" #include "UI_view2d.h" @@ -86,43 +86,10 @@ #include "paint_intern.h" -typedef struct UndoImageTile { - struct UndoImageTile *next, *prev; - - char idname[MAX_ID_NAME]; /* name instead of pointer*/ - char ibufname[IMB_FILENAME_SIZE]; - - union { - float *fp; - unsigned int *uint; - void *pt; - } rect; - - unsigned short *mask; - - int x, y; - - Image *ima; - short source, use_float; - char gen_type; - bool valid; -} UndoImageTile; - /* this is a static resource for non-globality, * Maybe it should be exposed as part of the * paint operation, but for now just give a public interface */ static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0}; -static SpinLock undolock; - -void image_undo_init_locks(void) -{ - BLI_spin_init(&undolock); -} - -void image_undo_end_locks(void) -{ - BLI_spin_end(&undolock); -} ImagePaintPartialRedraw *get_imapaintpartial(void) { @@ -134,296 +101,6 @@ void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr) imapaintpartial = *ippr; } -/* UNDO */ -typedef enum { - COPY = 0, - RESTORE = 1, - RESTORE_COPY = 2 -} CopyMode; - -static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, CopyMode mode) -{ - if (mode == COPY) { - /* 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(float *, tmpibuf->rect_float, tile->rect.fp); - } - else { - SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint); - } - } - else { - if (mode == RESTORE_COPY) { - IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE, - tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE); - } - /* swap to the tmpbuf for easy copying */ - if (ibuf->rect_float) { - SWAP(float *, tmpibuf->rect_float, tile->rect.fp); - } - else { - SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint); - } - - IMB_rectcpy(ibuf, tmpibuf, tile->x * IMAPAINT_TILE_SIZE, - tile->y * IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE); - - if (mode == RESTORE) { - if (ibuf->rect_float) { - SWAP(float *, tmpibuf->rect_float, tile->rect.fp); - } - else { - SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint); - } - } - } -} - -void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask, bool validate) -{ - ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); - UndoImageTile *tile; - short use_float = ibuf->rect_float ? 1 : 0; - - for (tile = lb->first; tile; tile = tile->next) { - if (tile->x == x_tile && tile->y == y_tile && ima->gen_type == tile->gen_type && ima->source == tile->source) { - if (tile->use_float == use_float) { - if (STREQ(tile->idname, ima->id.name) && STREQ(tile->ibufname, ibuf->name)) { - if (mask) { - /* allocate mask if requested */ - if (!tile->mask) { - tile->mask = MEM_callocN(sizeof(unsigned short) * IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE, - "UndoImageTile.mask"); - } - - *mask = tile->mask; - } - if (validate) - tile->valid = true; - - return tile->rect.pt; - } - } - } - } - - return NULL; -} - -void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile, unsigned short **mask, bool **valid, bool proj, bool find_prev) -{ - ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); - UndoImageTile *tile; - int allocsize; - short use_float = ibuf->rect_float ? 1 : 0; - void *data; - - /* check if tile is already pushed */ - - /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */ - if (find_prev) { - data = image_undo_find_tile(ima, ibuf, x_tile, y_tile, mask, true); - if (data) - return data; - } - - if (*tmpibuf == NULL) - *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect); - - tile = MEM_callocN(sizeof(UndoImageTile), "UndoImageTile"); - BLI_strncpy(tile->idname, ima->id.name, sizeof(tile->idname)); - tile->x = x_tile; - tile->y = y_tile; - - /* add mask explicitly here */ - if (mask) - *mask = tile->mask = MEM_callocN(sizeof(unsigned short) * IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE, - "UndoImageTile.mask"); - - allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4; - allocsize *= (ibuf->rect_float) ? sizeof(float) : sizeof(char); - tile->rect.pt = MEM_mapallocN(allocsize, "UndeImageTile.rect"); - - BLI_strncpy(tile->ibufname, ibuf->name, sizeof(tile->ibufname)); - - tile->gen_type = ima->gen_type; - tile->source = ima->source; - tile->use_float = use_float; - tile->valid = true; - tile->ima = ima; - - if (valid) - *valid = &tile->valid; - - undo_copy_tile(tile, *tmpibuf, ibuf, COPY); - - if (proj) - BLI_spin_lock(&undolock); - - undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, allocsize); - BLI_addtail(lb, tile); - - if (proj) - BLI_spin_unlock(&undolock); - - return tile->rect.pt; -} - -void image_undo_remove_masks(void) -{ - ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); - UndoImageTile *tile; - - for (tile = lb->first; tile; tile = tile->next) { - if (tile->mask) { - MEM_freeN(tile->mask); - tile->mask = NULL; - } - } -} - -static void image_undo_restore_runtime(ListBase *lb) -{ - ImBuf *ibuf, *tmpibuf; - UndoImageTile *tile; - - tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, - IB_rectfloat | IB_rect); - - for (tile = lb->first; tile; tile = tile->next) { - Image *ima = tile->ima; - ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); - - undo_copy_tile(tile, tmpibuf, ibuf, RESTORE); - - GPU_free_image(ima); /* force OpenGL reload (maybe partial update will operate better?) */ - if (ibuf->rect_float) - ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */ - if (ibuf->mipmap[0]) - ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */ - ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; - - BKE_image_release_ibuf(ima, ibuf, NULL); - } - - IMB_freeImBuf(tmpibuf); -} - -void ED_image_undo_restore(bContext *C, ListBase *lb) -{ - Main *bmain = CTX_data_main(C); - Image *ima = NULL; - ImBuf *ibuf, *tmpibuf; - UndoImageTile *tile; - - tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, - IB_rectfloat | IB_rect); - - for (tile = lb->first; tile; tile = tile->next) { - short use_float; - - /* find image based on name, pointer becomes invalid with global undo */ - if (ima && STREQ(tile->idname, ima->id.name)) { - /* ima is valid */ - } - else { - ima = BLI_findstring(&bmain->image, tile->idname, offsetof(ID, name)); - } - - ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); - - if (ima && ibuf && !STREQ(tile->ibufname, ibuf->name)) { - /* current ImBuf filename was changed, probably current frame - * was changed when painting on image sequence, rather than storing - * full image user (which isn't so obvious, btw) try to find ImBuf with - * matched file name in list of already loaded images */ - - BKE_image_release_ibuf(ima, ibuf, NULL); - - ibuf = BKE_image_get_ibuf_with_name(ima, tile->ibufname); - } - - if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) { - BKE_image_release_ibuf(ima, ibuf, NULL); - continue; - } - - if (ima->gen_type != tile->gen_type || ima->source != tile->source) { - BKE_image_release_ibuf(ima, ibuf, NULL); - continue; - } - - use_float = ibuf->rect_float ? 1 : 0; - - if (use_float != tile->use_float) { - BKE_image_release_ibuf(ima, ibuf, NULL); - continue; - } - - undo_copy_tile(tile, tmpibuf, ibuf, RESTORE_COPY); - - GPU_free_image(ima); /* force OpenGL reload */ - if (ibuf->rect_float) - ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */ - if (ibuf->mipmap[0]) - ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */ - ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; - - DAG_id_tag_update(&ima->id, 0); - - BKE_image_release_ibuf(ima, ibuf, NULL); - } - - IMB_freeImBuf(tmpibuf); -} - -void ED_image_undo_free(ListBase *lb) -{ - UndoImageTile *tile; - - for (tile = lb->first; tile; tile = tile->next) - MEM_freeN(tile->rect.pt); -} - -static void image_undo_end(void) -{ - ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); - UndoImageTile *tile; - int deallocsize = 0; - int allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4; - - /* first dispose of invalid tiles (may happen due to drag dot for instance) */ - for (tile = lb->first; tile;) { - if (!tile->valid) { - UndoImageTile *tmp_tile = tile->next; - deallocsize += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char)); - MEM_freeN(tile->rect.pt); - BLI_freelinkN(lb, tile); - tile = tmp_tile; - } - else { - tile = tile->next; - } - } - - /* don't forget to remove the size of deallocated tiles */ - undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, -deallocsize); - - ED_undo_paint_push_end(UNDO_PAINT_IMAGE); -} - -static void image_undo_invalidate(void) -{ - UndoImageTile *tile; - ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); - - for (tile = lb->first; tile; tile = tile->next) - tile->valid = false; -} - /* Imagepaint Partial Redraw & Dirty Region */ void ED_imapaint_clear_partial_redraw(void) @@ -453,7 +130,7 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int if (w == 0 || h == 0) return; - + if (!imapaintpartial.enabled) { imapaintpartial.x1 = x; imapaintpartial.y1 = y; @@ -470,12 +147,14 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int imapaint_region_tiles(ibuf, x, y, w, h, &tilex, &tiley, &tilew, &tileh); + ListBase *undo_tiles = ED_image_undo_get_tiles(); + for (ty = tiley; ty <= tileh; ty++) for (tx = tilex; tx <= tilew; tx++) - image_undo_push_tile(ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old); + image_undo_push_tile(undo_tiles, ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old); ibuf->userflags |= IB_BITMAPDIRTY; - + if (tmpibuf) IMB_freeImBuf(tmpibuf); } @@ -510,7 +189,7 @@ BlurKernel *paint_new_blur_kernel(Brush *br, bool proj) BlurKernel *kernel = MEM_mallocN(sizeof(BlurKernel), "blur kernel"); float radius; int side; - BlurKernelType type = br->blur_mode; + eBlurKernelType type = br->blur_mode; if (proj) { radius = 0.5f; @@ -624,13 +303,13 @@ static int image_paint_2d_clone_poll(bContext *C) } /************************ paint operator ************************/ -typedef enum TexPaintMode { +typedef enum eTexPaintMode { PAINT_MODE_2D, PAINT_MODE_3D_PROJECT -} TexPaintMode; +} eTexPaintMode; typedef struct PaintOperation { - TexPaintMode mode; + eTexPaintMode mode; void *custom_paint; @@ -655,8 +334,9 @@ bool paint_use_opacity_masking(Brush *brush) false : true; } -void paint_brush_color_get(struct Scene *scene, struct Brush *br, bool color_correction, bool invert, float distance, - float pressure, float color[3], struct ColorManagedDisplay *display) +void paint_brush_color_get( + struct Scene *scene, struct Brush *br, bool color_correction, bool invert, float distance, + float pressure, float color[3], struct ColorManagedDisplay *display) { if (invert) copy_v3_v3(color, BKE_brush_secondary_color_get(scene, br)); @@ -665,17 +345,17 @@ void paint_brush_color_get(struct Scene *scene, struct Brush *br, bool color_cor float color_gr[4]; switch (br->gradient_stroke_mode) { case BRUSH_GRADIENT_PRESSURE: - do_colorband(br->gradient, pressure, color_gr); + BKE_colorband_evaluate(br->gradient, pressure, color_gr); break; case BRUSH_GRADIENT_SPACING_REPEAT: { float coord = fmod(distance / br->gradient_spacing, 1.0); - do_colorband(br->gradient, coord, color_gr); + BKE_colorband_evaluate(br->gradient, coord, color_gr); break; } case BRUSH_GRADIENT_SPACING_CLAMP: { - do_colorband(br->gradient, distance / br->gradient_spacing, color_gr); + BKE_colorband_evaluate(br->gradient, distance / br->gradient_spacing, color_gr); break; } } @@ -741,7 +421,7 @@ static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const flo PaintOperation *pop = MEM_callocN(sizeof(PaintOperation), "PaintOperation"); /* caller frees */ Brush *brush = BKE_paint_brush(&settings->imapaint.paint); int mode = RNA_enum_get(op->ptr, "mode"); - view3d_set_viewcontext(C, &pop->vc); + ED_view3d_viewcontext_init(C, &pop->vc); copy_v2_v2(pop->prevmouse, mouse); copy_v2_v2(pop->startmouse, mouse); @@ -774,20 +454,11 @@ static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const flo } settings->imapaint.flag |= IMAGEPAINT_DRAWING; - ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name, - ED_image_undo_restore, ED_image_undo_free, NULL); + ED_image_undo_push_begin(op->type->name); return pop; } -/* restore painting image to previous state. Used for anchored and drag-dot style brushes*/ -static void paint_stroke_restore(void) -{ - ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); - image_undo_restore_runtime(lb); - image_undo_invalidate(); -} - static void paint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr) { PaintOperation *pop = paint_stroke_mode_data(stroke); @@ -824,7 +495,8 @@ static void paint_stroke_update_step(bContext *C, struct PaintStroke *stroke, Po BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * alphafac)); if ((brush->flag & BRUSH_DRAG_DOT) || (brush->flag & BRUSH_ANCHORED)) { - paint_stroke_restore(); + UndoStack *ustack = CTX_wm_manager(C)->undo_stack; + ED_image_undo_restore(ustack->step_init); } if (pop->mode == PAINT_MODE_3D_PROJECT) { @@ -901,7 +573,7 @@ static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke) WM_paint_cursor_end(CTX_wm_manager(C), pop->cursor); } - image_undo_end(); + ED_image_undo_push_end(); /* duplicate warning, see texpaint_init */ #if 0 @@ -1186,7 +858,7 @@ static int sample_color_exec(bContext *C, wmOperator *op) { Paint *paint = BKE_paint_get_active_from_context(C); Brush *brush = BKE_paint_brush(paint); - PaintMode mode = BKE_paintmode_get_active_from_context(C); + ePaintMode mode = BKE_paintmode_get_active_from_context(C); ARegion *ar = CTX_wm_region(C); wmWindow *win = CTX_wm_window(C); const bool show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0); @@ -1238,7 +910,7 @@ static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event RNA_int_set_array(op->ptr, "location", event->mval); - PaintMode mode = BKE_paintmode_get_active_from_context(C); + ePaintMode mode = BKE_paintmode_get_active_from_context(C); const bool use_sample_texture = (mode == ePaintTextureProjective) && !RNA_boolean_get(op->ptr, "merged"); paint_sample_color(C, ar, event->mval[0], event->mval[1], use_sample_texture, false); @@ -1274,7 +946,7 @@ static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_FINISHED; } - PaintMode mode = BKE_paintmode_get_active_from_context(C); + ePaintMode mode = BKE_paintmode_get_active_from_context(C); const bool use_sample_texture = (mode == ePaintTextureProjective) && !RNA_boolean_get(op->ptr, "merged"); switch (event->type) { @@ -1342,7 +1014,7 @@ static int texture_paint_toggle_poll(bContext *C) Object *ob = CTX_data_active_object(C); if (ob == NULL || ob->type != OB_MESH) return 0; - if (!ob->data || ID_IS_LINKED_DATABLOCK(ob->data)) + if (!ob->data || ID_IS_LINKED(ob->data)) return 0; if (CTX_data_edit_object(C)) return 0; @@ -1448,7 +1120,20 @@ void PAINT_OT_texture_paint_toggle(wmOperatorType *ot) static int brush_colors_flip_exec(bContext *C, wmOperator *UNUSED(op)) { UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; - Brush *br = image_paint_brush(C); + + Brush *br; + Object *ob = CTX_data_active_object(C); + if (!(ob && (ob->mode & OB_MODE_VERTEX_PAINT))) { + br = image_paint_brush(C); + } + else { + /* At the moment, wpaint does not support the color flipper. + * So for now we're only handling vpaint */ + ToolSettings *ts = CTX_data_tool_settings(C); + VPaint *vp = ts->vpaint; + br = BKE_paint_brush(&vp->paint); + } + if (ups->flag & UNIFIED_PAINT_COLOR) { swap_v3_v3(ups->rgb, ups->secondary_rgb); } @@ -1467,7 +1152,12 @@ static int brush_colors_flip_poll(bContext *C) if (br->imagepaint_tool == PAINT_TOOL_DRAW) return 1; } - + else { + Object *ob = CTX_data_active_object(C); + if (ob && (ob->mode & OB_MODE_VERTEX_PAINT)) { + return 1; + } + } return 0; } @@ -1489,15 +1179,17 @@ void PAINT_OT_brush_colors_flip(wmOperatorType *ot) void ED_imapaint_bucket_fill(struct bContext *C, float color[3], wmOperator *op) { + wmWindowManager *wm = CTX_wm_manager(C); SpaceImage *sima = CTX_wm_space_image(C); Image *ima = sima->image; - ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name, - ED_image_undo_restore, ED_image_undo_free, NULL); + BKE_undosys_step_push_init_with_type(wm->undo_stack, C, op->type->name, BKE_UNDOSYS_TYPE_IMAGE); + + ED_image_undo_push_begin(op->type->name); paint_2d_bucket_fill(C, color, NULL, NULL, NULL); - ED_undo_paint_push_end(UNDO_PAINT_IMAGE); + BKE_undosys_step_push(wm->undo_stack, C, op->type->name); DAG_id_tag_update(&ima->id, 0); } |