diff options
author | Jeroen Bakker <jeroen@blender.org> | 2022-02-22 11:57:11 +0300 |
---|---|---|
committer | Jeroen Bakker <jeroen@blender.org> | 2022-02-22 12:00:03 +0300 |
commit | 1d4ed6ba2964eb6ec9bf0e0648f8bb60ab7a914a (patch) | |
tree | 42a08f5efaaf685894e51109203aca146b422b03 /source/blender/editors/sculpt_paint/paint_image.c | |
parent | 1ec02b869587cf31414f8c2146614bc65a21725b (diff) |
Convert paint_image to cc.
Diffstat (limited to 'source/blender/editors/sculpt_paint/paint_image.c')
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_image.c | 1381 |
1 files changed, 0 insertions, 1381 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c deleted file mode 100644 index 2df42e6f532..00000000000 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ /dev/null @@ -1,1381 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2001-2002 NaN Holding BV. All rights reserved. */ - -/** \file - * \ingroup edsculpt - * \brief Functions to paint images in 2D and 3D. - */ - -#include <float.h> -#include <math.h> -#include <stdio.h> -#include <string.h> - -#include "MEM_guardedalloc.h" - -#include "BLI_blenlib.h" -#include "BLI_math.h" -#include "BLI_utildefines.h" - -#include "BLT_translation.h" - -#include "IMB_imbuf.h" -#include "IMB_imbuf_types.h" - -#include "DNA_brush_types.h" -#include "DNA_material_types.h" -#include "DNA_mesh_types.h" -#include "DNA_node_types.h" -#include "DNA_object_types.h" - -#include "BKE_brush.h" -#include "BKE_colorband.h" -#include "BKE_context.h" -#include "BKE_image.h" -#include "BKE_main.h" -#include "BKE_material.h" -#include "BKE_mesh.h" -#include "BKE_node.h" -#include "BKE_paint.h" -#include "BKE_undo_system.h" - -#include "NOD_texture.h" - -#include "DEG_depsgraph.h" - -#include "UI_interface.h" -#include "UI_view2d.h" - -#include "ED_image.h" -#include "ED_object.h" -#include "ED_paint.h" -#include "ED_screen.h" -#include "ED_view3d.h" - -#include "WM_api.h" -#include "WM_message.h" -#include "WM_toolsystem.h" -#include "WM_types.h" - -#include "RNA_access.h" -#include "RNA_define.h" - -#include "GPU_immediate.h" -#include "GPU_state.h" - -#include "IMB_colormanagement.h" - -#include "paint_intern.h" - -/** - * This is a static resource for non-global access. - * Maybe it should be exposed as part of the paint operation, - * but for now just give a public interface. - */ -static ImagePaintPartialRedraw imapaintpartial = {{0}}; - -ImagePaintPartialRedraw *get_imapaintpartial(void) -{ - return &imapaintpartial; -} - -void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr) -{ - imapaintpartial = *ippr; -} - -/* Imagepaint Partial Redraw & Dirty Region */ - -void ED_imapaint_clear_partial_redraw(void) -{ - BLI_rcti_init_minmax(&imapaintpartial.dirty_region); -} - -void imapaint_region_tiles( - ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th) -{ - int srcx = 0, srcy = 0; - - IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h); - - *tw = ((x + w - 1) >> ED_IMAGE_UNDO_TILE_BITS); - *th = ((y + h - 1) >> ED_IMAGE_UNDO_TILE_BITS); - *tx = (x >> ED_IMAGE_UNDO_TILE_BITS); - *ty = (y >> ED_IMAGE_UNDO_TILE_BITS); -} - -void ED_imapaint_dirty_region( - Image *ima, ImBuf *ibuf, ImageUser *iuser, int x, int y, int w, int h, bool find_old) -{ - ImBuf *tmpibuf = NULL; - int tilex, tiley, tilew, tileh, tx, ty; - int srcx = 0, srcy = 0; - - IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h); - - if (w == 0 || h == 0) { - return; - } - - rcti rect_to_merge; - BLI_rcti_init(&rect_to_merge, x, x + w, y, y + h); - BLI_rcti_do_minmax_rcti(&imapaintpartial.dirty_region, &rect_to_merge); - - imapaint_region_tiles(ibuf, x, y, w, h, &tilex, &tiley, &tilew, &tileh); - - ListBase *undo_tiles = ED_image_paint_tile_list_get(); - - for (ty = tiley; ty <= tileh; ty++) { - for (tx = tilex; tx <= tilew; tx++) { - ED_image_paint_tile_push( - undo_tiles, ima, ibuf, &tmpibuf, iuser, tx, ty, NULL, NULL, false, find_old); - } - } - - BKE_image_mark_dirty(ima, ibuf); - - if (tmpibuf) { - IMB_freeImBuf(tmpibuf); - } -} - -void imapaint_image_update( - SpaceImage *sima, Image *image, ImBuf *ibuf, ImageUser *iuser, short texpaint) -{ - if (BLI_rcti_is_empty(&imapaintpartial.dirty_region)) { - return; - } - - if (ibuf->mipmap[0]) { - ibuf->userflags |= IB_MIPMAP_INVALID; - } - - IMB_partial_display_buffer_update_delayed(ibuf, - imapaintpartial.dirty_region.xmin, - imapaintpartial.dirty_region.ymin, - imapaintpartial.dirty_region.xmax, - imapaintpartial.dirty_region.ymax); - - /* TODO: should set_tpage create ->rect? */ - if (texpaint || (sima && sima->lock)) { - const int w = BLI_rcti_size_x(&imapaintpartial.dirty_region); - const int h = BLI_rcti_size_y(&imapaintpartial.dirty_region); - /* Testing with partial update in uv editor too */ - BKE_image_update_gputexture( - image, iuser, imapaintpartial.dirty_region.xmin, imapaintpartial.dirty_region.ymin, w, h); - } -} - -BlurKernel *paint_new_blur_kernel(Brush *br, bool proj) -{ - int i, j; - BlurKernel *kernel = MEM_mallocN(sizeof(BlurKernel), "blur kernel"); - float radius; - int side; - eBlurKernelType type = br->blur_mode; - - if (proj) { - radius = 0.5f; - - side = kernel->side = 2; - kernel->side_squared = kernel->side * kernel->side; - kernel->wdata = MEM_mallocN(sizeof(float) * kernel->side_squared, "blur kernel data"); - kernel->pixel_len = radius; - } - else { - if (br->blur_kernel_radius <= 0) { - br->blur_kernel_radius = 1; - } - - radius = br->blur_kernel_radius; - - side = kernel->side = radius * 2 + 1; - kernel->side_squared = kernel->side * kernel->side; - kernel->wdata = MEM_mallocN(sizeof(float) * kernel->side_squared, "blur kernel data"); - kernel->pixel_len = br->blur_kernel_radius; - } - - switch (type) { - case KERNEL_BOX: - for (i = 0; i < kernel->side_squared; i++) { - kernel->wdata[i] = 1.0; - } - break; - - case KERNEL_GAUSSIAN: { - /* at 3.0 standard deviations distance, kernel is about zero */ - float standard_dev = radius / 3.0f; - - /* make the necessary adjustment to the value for use in the normal distribution formula */ - standard_dev = -standard_dev * standard_dev * 2; - - for (i = 0; i < side; i++) { - for (j = 0; j < side; j++) { - float idist = radius - i; - float jdist = radius - j; - float value = exp((idist * idist + jdist * jdist) / standard_dev); - - kernel->wdata[i + j * side] = value; - } - } - - break; - } - - default: - printf("unidentified kernel type, aborting\n"); - MEM_freeN(kernel->wdata); - MEM_freeN(kernel); - return NULL; - } - - return kernel; -} - -void paint_delete_blur_kernel(BlurKernel *kernel) -{ - if (kernel->wdata) { - MEM_freeN(kernel->wdata); - } -} - -/************************ image paint poll ************************/ - -static Brush *image_paint_brush(bContext *C) -{ - Scene *scene = CTX_data_scene(C); - ToolSettings *settings = scene->toolsettings; - - return BKE_paint_brush(&settings->imapaint.paint); -} - -static bool image_paint_poll_ex(bContext *C, bool check_tool) -{ - Object *obact; - - if (!image_paint_brush(C)) { - return false; - } - - obact = CTX_data_active_object(C); - if ((obact && obact->mode & OB_MODE_TEXTURE_PAINT) && CTX_wm_region_view3d(C)) { - if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) { - return true; - } - } - else { - SpaceImage *sima = CTX_wm_space_image(C); - - if (sima) { - if (sima->image != NULL && ID_IS_LINKED(sima->image)) { - return false; - } - ARegion *region = CTX_wm_region(C); - - if ((sima->mode == SI_MODE_PAINT) && region->regiontype == RGN_TYPE_WINDOW) { - return true; - } - } - } - - return false; -} - -static bool image_paint_poll(bContext *C) -{ - return image_paint_poll_ex(C, true); -} - -static bool image_paint_poll_ignore_tool(bContext *C) -{ - return image_paint_poll_ex(C, false); -} - -static bool image_paint_2d_clone_poll(bContext *C) -{ - Brush *brush = image_paint_brush(C); - - if (!CTX_wm_region_view3d(C) && image_paint_poll(C)) { - if (brush && (brush->imagepaint_tool == PAINT_TOOL_CLONE)) { - if (brush->clone.image) { - return true; - } - } - } - - return false; -} - -/************************ paint operator ************************/ -typedef enum eTexPaintMode { - PAINT_MODE_2D, - PAINT_MODE_3D_PROJECT, -} eTexPaintMode; - -typedef struct PaintOperation { - eTexPaintMode mode; - - void *stroke_handle; - - float prevmouse[2]; - float startmouse[2]; - double starttime; - - void *cursor; - ViewContext vc; -} PaintOperation; - -bool paint_use_opacity_masking(Brush *brush) -{ - return ((brush->flag & BRUSH_AIRBRUSH) || (brush->flag & BRUSH_DRAG_DOT) || - (brush->flag & BRUSH_ANCHORED) || - (ELEM(brush->imagepaint_tool, PAINT_TOOL_SMEAR, PAINT_TOOL_SOFTEN)) || - (brush->imagepaint_tool == PAINT_TOOL_FILL) || - (brush->flag & BRUSH_USE_GRADIENT) || - (brush->mtex.tex && !ELEM(brush->mtex.brush_map_mode, - MTEX_MAP_MODE_TILED, - MTEX_MAP_MODE_STENCIL, - MTEX_MAP_MODE_3D)) ? - 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) -{ - if (invert) { - copy_v3_v3(color, BKE_brush_secondary_color_get(scene, br)); - } - else { - if (br->flag & BRUSH_USE_GRADIENT) { - float color_gr[4]; - switch (br->gradient_stroke_mode) { - case BRUSH_GRADIENT_PRESSURE: - BKE_colorband_evaluate(br->gradient, pressure, color_gr); - break; - case BRUSH_GRADIENT_SPACING_REPEAT: { - float coord = fmod(distance / br->gradient_spacing, 1.0); - BKE_colorband_evaluate(br->gradient, coord, color_gr); - break; - } - case BRUSH_GRADIENT_SPACING_CLAMP: { - BKE_colorband_evaluate(br->gradient, distance / br->gradient_spacing, color_gr); - break; - } - } - /* Gradient / Colorband colors are not considered PROP_COLOR_GAMMA. - * Brush colors are expected to be in sRGB though. */ - IMB_colormanagement_scene_linear_to_srgb_v3(color_gr); - - copy_v3_v3(color, color_gr); - } - else { - copy_v3_v3(color, BKE_brush_color_get(scene, br)); - } - } - if (color_correction) { - IMB_colormanagement_display_to_scene_linear_v3(color, display); - } -} - -void paint_brush_init_tex(Brush *brush) -{ - /* init mtex nodes */ - if (brush) { - MTex *mtex = &brush->mtex; - if (mtex->tex && mtex->tex->nodetree) { - /* has internal flag to detect it only does it once */ - ntreeTexBeginExecTree(mtex->tex->nodetree); - } - mtex = &brush->mask_mtex; - if (mtex->tex && mtex->tex->nodetree) { - ntreeTexBeginExecTree(mtex->tex->nodetree); - } - } -} - -void paint_brush_exit_tex(Brush *brush) -{ - if (brush) { - MTex *mtex = &brush->mtex; - if (mtex->tex && mtex->tex->nodetree) { - ntreeTexEndExecTree(mtex->tex->nodetree->execdata); - } - mtex = &brush->mask_mtex; - if (mtex->tex && mtex->tex->nodetree) { - ntreeTexEndExecTree(mtex->tex->nodetree->execdata); - } - } -} - -static void gradient_draw_line(bContext *UNUSED(C), int x, int y, void *customdata) -{ - PaintOperation *pop = (PaintOperation *)customdata; - - if (pop) { - GPU_line_smooth(true); - GPU_blend(GPU_BLEND_ALPHA); - - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); - - ARegion *region = pop->vc.region; - - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - - GPU_line_width(4.0); - immUniformColor4ub(0, 0, 0, 255); - - immBegin(GPU_PRIM_LINES, 2); - immVertex2i(pos, x, y); - immVertex2i( - pos, pop->startmouse[0] + region->winrct.xmin, pop->startmouse[1] + region->winrct.ymin); - immEnd(); - - GPU_line_width(2.0); - immUniformColor4ub(255, 255, 255, 255); - - immBegin(GPU_PRIM_LINES, 2); - immVertex2i(pos, x, y); - immVertex2i( - pos, pop->startmouse[0] + region->winrct.xmin, pop->startmouse[1] + region->winrct.ymin); - immEnd(); - - immUnbindProgram(); - - GPU_blend(GPU_BLEND_NONE); - GPU_line_smooth(false); - } -} - -static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const float mouse[2]) -{ - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - Scene *scene = CTX_data_scene(C); - ToolSettings *settings = scene->toolsettings; - 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"); - ED_view3d_viewcontext_init(C, &pop->vc, depsgraph); - - copy_v2_v2(pop->prevmouse, mouse); - copy_v2_v2(pop->startmouse, mouse); - - /* initialize from context */ - if (CTX_wm_region_view3d(C)) { - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *ob = OBACT(view_layer); - bool uvs, mat, tex, stencil; - if (!ED_paint_proj_mesh_data_check(scene, ob, &uvs, &mat, &tex, &stencil)) { - ED_paint_data_warning(op->reports, uvs, mat, tex, stencil); - MEM_freeN(pop); - WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL); - return NULL; - } - pop->mode = PAINT_MODE_3D_PROJECT; - pop->stroke_handle = paint_proj_new_stroke(C, ob, mouse, mode); - } - else { - pop->mode = PAINT_MODE_2D; - pop->stroke_handle = paint_2d_new_stroke(C, op, mode); - } - - if (!pop->stroke_handle) { - MEM_freeN(pop); - return NULL; - } - - if ((brush->imagepaint_tool == PAINT_TOOL_FILL) && (brush->flag & BRUSH_USE_GRADIENT)) { - pop->cursor = WM_paint_cursor_activate( - SPACE_TYPE_ANY, RGN_TYPE_ANY, image_paint_poll, gradient_draw_line, pop); - } - - settings->imapaint.flag |= IMAGEPAINT_DRAWING; - ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D); - - return pop; -} - -static void paint_stroke_update_step(bContext *C, - wmOperator *UNUSED(op), - struct PaintStroke *stroke, - PointerRNA *itemptr) -{ - PaintOperation *pop = paint_stroke_mode_data(stroke); - Scene *scene = CTX_data_scene(C); - ToolSettings *toolsettings = CTX_data_tool_settings(C); - UnifiedPaintSettings *ups = &toolsettings->unified_paint_settings; - Brush *brush = BKE_paint_brush(&toolsettings->imapaint.paint); - - float alphafac = (brush->flag & BRUSH_ACCUMULATE) ? ups->overlap_factor : 1.0f; - - /* initial brush values. Maybe it should be considered moving these to stroke system */ - float startalpha = BKE_brush_alpha_get(scene, brush); - - float mouse[2]; - float pressure; - float size; - float distance = paint_stroke_distance_get(stroke); - int eraser; - - RNA_float_get_array(itemptr, "mouse", mouse); - pressure = RNA_float_get(itemptr, "pressure"); - eraser = RNA_boolean_get(itemptr, "pen_flip"); - size = RNA_float_get(itemptr, "size"); - - /* stroking with fill tool only acts on stroke end */ - if (brush->imagepaint_tool == PAINT_TOOL_FILL) { - copy_v2_v2(pop->prevmouse, mouse); - return; - } - - if (BKE_brush_use_alpha_pressure(brush)) { - BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * pressure * alphafac)); - } - else { - BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * alphafac)); - } - - if ((brush->flag & BRUSH_DRAG_DOT) || (brush->flag & BRUSH_ANCHORED)) { - UndoStack *ustack = CTX_wm_manager(C)->undo_stack; - ED_image_undo_restore(ustack->step_init); - } - - switch (pop->mode) { - case PAINT_MODE_2D: - paint_2d_stroke(pop->stroke_handle, pop->prevmouse, mouse, eraser, pressure, distance, size); - break; - - case PAINT_MODE_3D_PROJECT: - paint_proj_stroke( - C, pop->stroke_handle, pop->prevmouse, mouse, eraser, pressure, distance, size); - break; - } - - copy_v2_v2(pop->prevmouse, mouse); - - /* restore brush values */ - BKE_brush_alpha_set(scene, brush, startalpha); -} - -static void paint_stroke_redraw(const bContext *C, struct PaintStroke *stroke, bool final) -{ - PaintOperation *pop = paint_stroke_mode_data(stroke); - - switch (pop->mode) { - case PAINT_MODE_2D: - paint_2d_redraw(C, pop->stroke_handle, final); - break; - - case PAINT_MODE_3D_PROJECT: - paint_proj_redraw(C, pop->stroke_handle, final); - break; - } -} - -static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke) -{ - Scene *scene = CTX_data_scene(C); - ToolSettings *toolsettings = scene->toolsettings; - PaintOperation *pop = paint_stroke_mode_data(stroke); - Brush *brush = BKE_paint_brush(&toolsettings->imapaint.paint); - - toolsettings->imapaint.flag &= ~IMAGEPAINT_DRAWING; - - if (brush->imagepaint_tool == PAINT_TOOL_FILL) { - if (brush->flag & BRUSH_USE_GRADIENT) { - switch (pop->mode) { - case PAINT_MODE_2D: - paint_2d_gradient_fill(C, brush, pop->startmouse, pop->prevmouse, pop->stroke_handle); - break; - - case PAINT_MODE_3D_PROJECT: - paint_proj_stroke(C, - pop->stroke_handle, - pop->startmouse, - pop->prevmouse, - paint_stroke_flipped(stroke), - 1.0, - 0.0, - BKE_brush_size_get(scene, brush)); - /* two redraws, one for GPU update, one for notification */ - paint_proj_redraw(C, pop->stroke_handle, false); - paint_proj_redraw(C, pop->stroke_handle, true); - break; - } - } - else { - switch (pop->mode) { - case PAINT_MODE_2D: - float color[3]; - if (paint_stroke_inverted(stroke)) { - srgb_to_linearrgb_v3_v3(color, BKE_brush_secondary_color_get(scene, brush)); - } - else { - srgb_to_linearrgb_v3_v3(color, BKE_brush_color_get(scene, brush)); - } - paint_2d_bucket_fill( - C, color, brush, pop->startmouse, pop->prevmouse, pop->stroke_handle); - break; - - case PAINT_MODE_3D_PROJECT: - paint_proj_stroke(C, - pop->stroke_handle, - pop->startmouse, - pop->prevmouse, - paint_stroke_flipped(stroke), - 1.0, - 0.0, - BKE_brush_size_get(scene, brush)); - /* two redraws, one for GPU update, one for notification */ - paint_proj_redraw(C, pop->stroke_handle, false); - paint_proj_redraw(C, pop->stroke_handle, true); - break; - } - } - } - - switch (pop->mode) { - case PAINT_MODE_2D: - paint_2d_stroke_done(pop->stroke_handle); - break; - - case PAINT_MODE_3D_PROJECT: - paint_proj_stroke_done(pop->stroke_handle); - break; - } - - if (pop->cursor) { - WM_paint_cursor_end(pop->cursor); - } - - ED_image_undo_push_end(); - - /* duplicate warning, see texpaint_init */ -#if 0 - if (pop->s.warnmultifile) { - BKE_reportf(op->reports, - RPT_WARNING, - "Image requires 4 color channels to paint: %s", - pop->s.warnmultifile); - } - if (pop->s.warnpackedfile) { - BKE_reportf(op->reports, - RPT_WARNING, - "Packed MultiLayer files cannot be painted: %s", - pop->s.warnpackedfile); - } -#endif - MEM_freeN(pop); -} - -static bool paint_stroke_test_start(bContext *C, wmOperator *op, const float mouse[2]) -{ - PaintOperation *pop; - - /* TODO: Should avoid putting this here. Instead, last position should be requested - * from stroke system. */ - - if (!(pop = texture_paint_init(C, op, mouse))) { - return false; - } - - paint_stroke_set_mode_data(op->customdata, pop); - - return true; -} - -static int paint_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - int retval; - - op->customdata = paint_stroke_new(C, - op, - NULL, - paint_stroke_test_start, - paint_stroke_update_step, - paint_stroke_redraw, - paint_stroke_done, - event->type); - - if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) { - paint_stroke_free(C, op, op->customdata); - return OPERATOR_FINISHED; - } - /* add modal handler */ - WM_event_add_modal_handler(C, op); - - OPERATOR_RETVAL_CHECK(retval); - BLI_assert(retval == OPERATOR_RUNNING_MODAL); - - return OPERATOR_RUNNING_MODAL; -} - -static int paint_exec(bContext *C, wmOperator *op) -{ - PropertyRNA *strokeprop; - PointerRNA firstpoint; - float mouse[2]; - - strokeprop = RNA_struct_find_property(op->ptr, "stroke"); - - if (!RNA_property_collection_lookup_int(op->ptr, strokeprop, 0, &firstpoint)) { - return OPERATOR_CANCELLED; - } - - RNA_float_get_array(&firstpoint, "mouse", mouse); - - op->customdata = paint_stroke_new(C, - op, - NULL, - paint_stroke_test_start, - paint_stroke_update_step, - paint_stroke_redraw, - paint_stroke_done, - 0); - /* frees op->customdata */ - return paint_stroke_exec(C, op, op->customdata); -} - -static int paint_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - return paint_stroke_modal(C, op, event, op->customdata); -} - -static void paint_cancel(bContext *C, wmOperator *op) -{ - paint_stroke_cancel(C, op, op->customdata); -} - -void PAINT_OT_image_paint(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Image Paint"; - ot->idname = "PAINT_OT_image_paint"; - ot->description = "Paint a stroke into the image"; - - /* api callbacks */ - ot->invoke = paint_invoke; - ot->modal = paint_modal; - ot->exec = paint_exec; - ot->poll = image_paint_poll; - ot->cancel = paint_cancel; - - /* flags */ - ot->flag = OPTYPE_BLOCKING; - - paint_stroke_operator_properties(ot); -} - -bool get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy) -{ - ScrArea *area = CTX_wm_area(C); - if (area && area->spacetype == SPACE_IMAGE) { - SpaceImage *sima = area->spacedata.first; - if (sima->mode == SI_MODE_PAINT) { - ARegion *region = CTX_wm_region(C); - ED_space_image_get_zoom(sima, region, zoomx, zoomy); - return true; - } - } - - *zoomx = *zoomy = 1; - - return false; -} - -/************************ cursor drawing *******************************/ - -static void toggle_paint_cursor(Scene *scene, bool enable) -{ - ToolSettings *settings = scene->toolsettings; - Paint *p = &settings->imapaint.paint; - - if (p->paint_cursor && !enable) { - WM_paint_cursor_end(p->paint_cursor); - p->paint_cursor = NULL; - paint_cursor_delete_textures(); - } - else if (enable) { - paint_cursor_start(p, image_paint_poll); - } -} - -void ED_space_image_paint_update(Main *bmain, wmWindowManager *wm, Scene *scene) -{ - ToolSettings *settings = scene->toolsettings; - ImagePaintSettings *imapaint = &settings->imapaint; - bool enabled = false; - - LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { - bScreen *screen = WM_window_get_active_screen(win); - - LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { - if (area->spacetype == SPACE_IMAGE) { - if (((SpaceImage *)area->spacedata.first)->mode == SI_MODE_PAINT) { - enabled = true; - } - } - } - } - - if (enabled) { - BKE_paint_init(bmain, scene, PAINT_MODE_TEXTURE_2D, PAINT_CURSOR_TEXTURE_PAINT); - - paint_cursor_start(&imapaint->paint, image_paint_poll); - } - else { - paint_cursor_delete_textures(); - } -} - -/************************ grab clone operator ************************/ - -typedef struct GrabClone { - float startoffset[2]; - int startx, starty; -} GrabClone; - -static void grab_clone_apply(bContext *C, wmOperator *op) -{ - Brush *brush = image_paint_brush(C); - float delta[2]; - - RNA_float_get_array(op->ptr, "delta", delta); - add_v2_v2(brush->clone.offset, delta); - ED_region_tag_redraw(CTX_wm_region(C)); -} - -static int grab_clone_exec(bContext *C, wmOperator *op) -{ - grab_clone_apply(C, op); - - return OPERATOR_FINISHED; -} - -static int grab_clone_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - Brush *brush = image_paint_brush(C); - GrabClone *cmv; - - cmv = MEM_callocN(sizeof(GrabClone), "GrabClone"); - copy_v2_v2(cmv->startoffset, brush->clone.offset); - cmv->startx = event->xy[0]; - cmv->starty = event->xy[1]; - op->customdata = cmv; - - WM_event_add_modal_handler(C, op); - - return OPERATOR_RUNNING_MODAL; -} - -static int grab_clone_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - Brush *brush = image_paint_brush(C); - ARegion *region = CTX_wm_region(C); - GrabClone *cmv = op->customdata; - float startfx, startfy, fx, fy, delta[2]; - int xmin = region->winrct.xmin, ymin = region->winrct.ymin; - - switch (event->type) { - case LEFTMOUSE: - case MIDDLEMOUSE: - case RIGHTMOUSE: /* XXX hardcoded */ - MEM_freeN(op->customdata); - return OPERATOR_FINISHED; - case MOUSEMOVE: - /* mouse moved, so move the clone image */ - UI_view2d_region_to_view( - ®ion->v2d, cmv->startx - xmin, cmv->starty - ymin, &startfx, &startfy); - UI_view2d_region_to_view(®ion->v2d, event->xy[0] - xmin, event->xy[1] - ymin, &fx, &fy); - - delta[0] = fx - startfx; - delta[1] = fy - startfy; - RNA_float_set_array(op->ptr, "delta", delta); - - copy_v2_v2(brush->clone.offset, cmv->startoffset); - - grab_clone_apply(C, op); - break; - } - - return OPERATOR_RUNNING_MODAL; -} - -static void grab_clone_cancel(bContext *UNUSED(C), wmOperator *op) -{ - MEM_freeN(op->customdata); -} - -void PAINT_OT_grab_clone(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Grab Clone"; - ot->idname = "PAINT_OT_grab_clone"; - ot->description = "Move the clone source image"; - - /* api callbacks */ - ot->exec = grab_clone_exec; - ot->invoke = grab_clone_invoke; - ot->modal = grab_clone_modal; - ot->cancel = grab_clone_cancel; - ot->poll = image_paint_2d_clone_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; - - /* properties */ - RNA_def_float_vector(ot->srna, - "delta", - 2, - NULL, - -FLT_MAX, - FLT_MAX, - "Delta", - "Delta offset of clone image in 0.0 to 1.0 coordinates", - -1.0f, - 1.0f); -} - -/******************** sample color operator ********************/ -typedef struct { - bool show_cursor; - short launch_event; - float initcolor[3]; - bool sample_palette; -} SampleColorData; - -static void sample_color_update_header(SampleColorData *data, bContext *C) -{ - char msg[UI_MAX_DRAW_STR]; - ScrArea *area = CTX_wm_area(C); - - if (area) { - BLI_snprintf(msg, - sizeof(msg), - TIP_("Sample color for %s"), - !data->sample_palette ? - TIP_("Brush. Use Left Click to sample for palette instead") : - TIP_("Palette. Use Left Click to sample more colors")); - ED_workspace_status_text(C, msg); - } -} - -static int sample_color_exec(bContext *C, wmOperator *op) -{ - Paint *paint = BKE_paint_get_active_from_context(C); - Brush *brush = BKE_paint_brush(paint); - ePaintMode mode = BKE_paintmode_get_active_from_context(C); - ARegion *region = CTX_wm_region(C); - wmWindow *win = CTX_wm_window(C); - const bool show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0); - int location[2]; - paint->flags &= ~PAINT_SHOW_BRUSH; - - /* force redraw without cursor */ - WM_paint_cursor_tag_redraw(win, region); - WM_redraw_windows(C); - - RNA_int_get_array(op->ptr, "location", location); - const bool use_palette = RNA_boolean_get(op->ptr, "palette"); - const bool use_sample_texture = (mode == PAINT_MODE_TEXTURE_3D) && - !RNA_boolean_get(op->ptr, "merged"); - - paint_sample_color(C, region, location[0], location[1], use_sample_texture, use_palette); - - if (show_cursor) { - paint->flags |= PAINT_SHOW_BRUSH; - } - - WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush); - - return OPERATOR_FINISHED; -} - -static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - Scene *scene = CTX_data_scene(C); - Paint *paint = BKE_paint_get_active_from_context(C); - Brush *brush = BKE_paint_brush(paint); - SampleColorData *data = MEM_mallocN(sizeof(SampleColorData), "sample color custom data"); - ARegion *region = CTX_wm_region(C); - wmWindow *win = CTX_wm_window(C); - - data->launch_event = WM_userdef_event_type_from_keymap_type(event->type); - data->show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0); - copy_v3_v3(data->initcolor, BKE_brush_color_get(scene, brush)); - data->sample_palette = false; - op->customdata = data; - paint->flags &= ~PAINT_SHOW_BRUSH; - - sample_color_update_header(data, C); - - WM_event_add_modal_handler(C, op); - - /* force redraw without cursor */ - WM_paint_cursor_tag_redraw(win, region); - WM_redraw_windows(C); - - RNA_int_set_array(op->ptr, "location", event->mval); - - ePaintMode mode = BKE_paintmode_get_active_from_context(C); - const bool use_sample_texture = (mode == PAINT_MODE_TEXTURE_3D) && - !RNA_boolean_get(op->ptr, "merged"); - - paint_sample_color(C, region, event->mval[0], event->mval[1], use_sample_texture, false); - WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER); - - WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush); - - return OPERATOR_RUNNING_MODAL; -} - -static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - Scene *scene = CTX_data_scene(C); - SampleColorData *data = op->customdata; - Paint *paint = BKE_paint_get_active_from_context(C); - Brush *brush = BKE_paint_brush(paint); - - if ((event->type == data->launch_event) && (event->val == KM_RELEASE)) { - if (data->show_cursor) { - paint->flags |= PAINT_SHOW_BRUSH; - } - - if (data->sample_palette) { - BKE_brush_color_set(scene, brush, data->initcolor); - RNA_boolean_set(op->ptr, "palette", true); - } - WM_cursor_modal_restore(CTX_wm_window(C)); - MEM_freeN(data); - ED_workspace_status_text(C, NULL); - - return OPERATOR_FINISHED; - } - - ePaintMode mode = BKE_paintmode_get_active_from_context(C); - const bool use_sample_texture = (mode == PAINT_MODE_TEXTURE_3D) && - !RNA_boolean_get(op->ptr, "merged"); - - switch (event->type) { - case MOUSEMOVE: { - ARegion *region = CTX_wm_region(C); - RNA_int_set_array(op->ptr, "location", event->mval); - paint_sample_color(C, region, event->mval[0], event->mval[1], use_sample_texture, false); - WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush); - break; - } - - case LEFTMOUSE: - if (event->val == KM_PRESS) { - ARegion *region = CTX_wm_region(C); - RNA_int_set_array(op->ptr, "location", event->mval); - paint_sample_color(C, region, event->mval[0], event->mval[1], use_sample_texture, true); - if (!data->sample_palette) { - data->sample_palette = true; - sample_color_update_header(data, C); - } - WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush); - } - break; - } - - return OPERATOR_RUNNING_MODAL; -} - -static bool sample_color_poll(bContext *C) -{ - return (image_paint_poll_ignore_tool(C) || vertex_paint_poll_ignore_tool(C)); -} - -void PAINT_OT_sample_color(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Sample Color"; - ot->idname = "PAINT_OT_sample_color"; - ot->description = "Use the mouse to sample a color in the image"; - - /* api callbacks */ - ot->exec = sample_color_exec; - ot->invoke = sample_color_invoke; - ot->modal = sample_color_modal; - ot->poll = sample_color_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - PropertyRNA *prop; - - prop = RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "", 0, 16384); - RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); - - RNA_def_boolean(ot->srna, "merged", 0, "Sample Merged", "Sample the output display color"); - RNA_def_boolean(ot->srna, "palette", 0, "Add to Palette", ""); -} - -/******************** texture paint toggle operator ********************/ - -void ED_object_texture_paint_mode_enter_ex(Main *bmain, Scene *scene, Object *ob) -{ - Image *ima = NULL; - ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; - - /* This has to stay here to regenerate the texture paint - * cache in case we are loading a file */ - BKE_texpaint_slots_refresh_object(scene, ob); - - ED_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); - - /* entering paint mode also sets image to editors */ - if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) { - /* set the current material active paint slot on image editor */ - Material *ma = BKE_object_material_get(ob, ob->actcol); - - if (ma && ma->texpaintslot) { - ima = ma->texpaintslot[ma->paint_active_slot].ima; - } - } - else if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) { - ima = imapaint->canvas; - } - - if (ima) { - wmWindowManager *wm = bmain->wm.first; - for (wmWindow *win = wm->windows.first; win; win = win->next) { - const bScreen *screen = WM_window_get_active_screen(win); - for (ScrArea *area = screen->areabase.first; area; area = area->next) { - SpaceLink *sl = area->spacedata.first; - if (sl->spacetype == SPACE_IMAGE) { - SpaceImage *sima = (SpaceImage *)sl; - - if (!sima->pin) { - ED_space_image_set(bmain, sima, ima, true); - } - } - } - } - } - - ob->mode |= OB_MODE_TEXTURE_PAINT; - - BKE_paint_init(bmain, scene, PAINT_MODE_TEXTURE_3D, PAINT_CURSOR_TEXTURE_PAINT); - - BKE_paint_toolslots_brush_validate(bmain, &imapaint->paint); - - if (U.glreslimit != 0) { - BKE_image_free_all_gputextures(bmain); - } - BKE_image_paint_set_mipmap(bmain, 0); - - toggle_paint_cursor(scene, true); - - Mesh *me = BKE_mesh_from_object(ob); - BLI_assert(me != NULL); - DEG_id_tag_update(&me->id, ID_RECALC_COPY_ON_WRITE); - WM_main_add_notifier(NC_SCENE | ND_MODE, scene); -} - -void ED_object_texture_paint_mode_enter(bContext *C) -{ - Main *bmain = CTX_data_main(C); - Object *ob = CTX_data_active_object(C); - Scene *scene = CTX_data_scene(C); - ED_object_texture_paint_mode_enter_ex(bmain, scene, ob); -} - -void ED_object_texture_paint_mode_exit_ex(Main *bmain, Scene *scene, Object *ob) -{ - ob->mode &= ~OB_MODE_TEXTURE_PAINT; - - if (U.glreslimit != 0) { - BKE_image_free_all_gputextures(bmain); - } - BKE_image_paint_set_mipmap(bmain, 1); - toggle_paint_cursor(scene, false); - - Mesh *me = BKE_mesh_from_object(ob); - BLI_assert(me != NULL); - DEG_id_tag_update(&me->id, ID_RECALC_COPY_ON_WRITE); - WM_main_add_notifier(NC_SCENE | ND_MODE, scene); -} - -void ED_object_texture_paint_mode_exit(bContext *C) -{ - Main *bmain = CTX_data_main(C); - Object *ob = CTX_data_active_object(C); - Scene *scene = CTX_data_scene(C); - ED_object_texture_paint_mode_exit_ex(bmain, scene, ob); -} - -static bool texture_paint_toggle_poll(bContext *C) -{ - Object *ob = CTX_data_active_object(C); - if (ob == NULL || ob->type != OB_MESH) { - return false; - } - if (!ob->data || ID_IS_LINKED(ob->data)) { - return false; - } - - return true; -} - -static int texture_paint_toggle_exec(bContext *C, wmOperator *op) -{ - struct wmMsgBus *mbus = CTX_wm_message_bus(C); - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - Object *ob = CTX_data_active_object(C); - const int mode_flag = OB_MODE_TEXTURE_PAINT; - const bool is_mode_set = (ob->mode & mode_flag) != 0; - - if (!is_mode_set) { - if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { - return OPERATOR_CANCELLED; - } - } - - if (ob->mode & mode_flag) { - ED_object_texture_paint_mode_exit_ex(bmain, scene, ob); - } - else { - ED_object_texture_paint_mode_enter_ex(bmain, scene, ob); - } - - WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode); - - WM_toolsystem_update_from_context_view3d(C); - - return OPERATOR_FINISHED; -} - -void PAINT_OT_texture_paint_toggle(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Texture Paint Toggle"; - ot->idname = "PAINT_OT_texture_paint_toggle"; - ot->description = "Toggle texture paint mode in 3D view"; - - /* api callbacks */ - ot->exec = texture_paint_toggle_exec; - ot->poll = texture_paint_toggle_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -static int brush_colors_flip_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Scene *scene = CTX_data_scene(C); - UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; - - Paint *paint = BKE_paint_get_active_from_context(C); - Brush *br = BKE_paint_brush(paint); - - if (ups->flag & UNIFIED_PAINT_COLOR) { - swap_v3_v3(ups->rgb, ups->secondary_rgb); - } - else if (br) { - swap_v3_v3(br->rgb, br->secondary_rgb); - } - else { - return OPERATOR_CANCELLED; - } - - WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, br); - - return OPERATOR_FINISHED; -} - -static bool brush_colors_flip_poll(bContext *C) -{ - if (image_paint_poll(C)) { - Brush *br = image_paint_brush(C); - if (ELEM(br->imagepaint_tool, PAINT_TOOL_DRAW, PAINT_TOOL_FILL)) { - return true; - } - } - else { - Object *ob = CTX_data_active_object(C); - if (ob != NULL) { - if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_TEXTURE_PAINT | OB_MODE_SCULPT)) { - return true; - } - } - } - return false; -} - -void PAINT_OT_brush_colors_flip(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Swap Colors"; - ot->idname = "PAINT_OT_brush_colors_flip"; - ot->description = "Swap primary and secondary brush colors"; - - /* api callbacks */ - ot->exec = brush_colors_flip_exec; - ot->poll = brush_colors_flip_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -void ED_imapaint_bucket_fill(struct bContext *C, - float color[3], - wmOperator *op, - const int mouse[2]) -{ - SpaceImage *sima = CTX_wm_space_image(C); - - if (sima && sima->image) { - Image *ima = sima->image; - - ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D); - - const float mouse_init[2] = {mouse[0], mouse[1]}; - paint_2d_bucket_fill(C, color, NULL, mouse_init, NULL, NULL); - - ED_image_undo_push_end(); - - DEG_id_tag_update(&ima->id, 0); - } -} - -static bool texture_paint_poll(bContext *C) -{ - if (texture_paint_toggle_poll(C)) { - if (CTX_data_active_object(C)->mode & OB_MODE_TEXTURE_PAINT) { - return true; - } - } - - return false; -} - -bool image_texture_paint_poll(bContext *C) -{ - return (texture_paint_poll(C) || image_paint_poll(C)); -} - -bool facemask_paint_poll(bContext *C) -{ - return BKE_paint_select_face_test(CTX_data_active_object(C)); -} - -bool vert_paint_poll(bContext *C) -{ - return BKE_paint_select_vert_test(CTX_data_active_object(C)); -} - -bool mask_paint_poll(bContext *C) -{ - return BKE_paint_select_elem_test(CTX_data_active_object(C)); -} |