2011-02-23 10:52:22 +00:00
|
|
|
/*
|
2009-02-19 23:53:40 +00:00
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
2010-02-12 13:34:04 +00:00
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2009-02-19 23:53:40 +00:00
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* The Original Code is: some of this file.
|
|
|
|
*/
|
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
* \ingroup edsculpt
|
|
|
|
* \brief Functions to paint images in 2D and 3D.
|
2011-02-27 20:29:51 +00:00
|
|
|
*/
|
|
|
|
|
2009-02-19 23:53:40 +00:00
|
|
|
#include <float.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
#include "BLI_math.h"
|
2009-02-19 23:53:40 +00:00
|
|
|
#include "BLI_blenlib.h"
|
2011-01-07 18:36:47 +00:00
|
|
|
#include "BLI_utildefines.h"
|
|
|
|
|
2016-05-14 10:00:52 +02:00
|
|
|
#include "BLT_translation.h"
|
2009-02-19 23:53:40 +00:00
|
|
|
|
|
|
|
#include "IMB_imbuf.h"
|
|
|
|
#include "IMB_imbuf_types.h"
|
|
|
|
|
2011-03-03 18:53:07 +00:00
|
|
|
#include "DNA_brush_types.h"
|
2018-06-26 12:31:06 +02:00
|
|
|
#include "DNA_mesh_types.h"
|
2011-09-05 21:01:50 +00:00
|
|
|
#include "DNA_node_types.h"
|
2009-02-19 23:53:40 +00:00
|
|
|
#include "DNA_object_types.h"
|
|
|
|
|
2017-12-07 15:36:26 +11:00
|
|
|
#include "BKE_colorband.h"
|
2009-02-19 23:53:40 +00:00
|
|
|
#include "BKE_context.h"
|
|
|
|
#include "BKE_brush.h"
|
|
|
|
#include "BKE_main.h"
|
2014-07-21 12:02:05 +02:00
|
|
|
#include "BKE_material.h"
|
2018-06-26 12:31:06 +02:00
|
|
|
#include "BKE_mesh.h"
|
2011-03-03 18:53:07 +00:00
|
|
|
#include "BKE_node.h"
|
2009-08-17 04:40:59 +00:00
|
|
|
#include "BKE_paint.h"
|
2018-03-19 14:17:59 +01:00
|
|
|
#include "BKE_undo_system.h"
|
|
|
|
|
2009-02-19 23:53:40 +00:00
|
|
|
|
2017-06-08 10:14:53 +02:00
|
|
|
#include "DEG_depsgraph.h"
|
|
|
|
|
2016-05-14 10:00:52 +02:00
|
|
|
#include "UI_interface.h"
|
2009-02-19 23:53:40 +00:00
|
|
|
#include "UI_view2d.h"
|
|
|
|
|
|
|
|
#include "ED_image.h"
|
2013-08-29 10:34:09 +00:00
|
|
|
#include "ED_object.h"
|
2014-06-23 21:59:34 +10:00
|
|
|
#include "ED_paint.h"
|
2009-02-19 23:53:40 +00:00
|
|
|
#include "ED_screen.h"
|
|
|
|
#include "ED_view3d.h"
|
|
|
|
|
|
|
|
#include "WM_api.h"
|
|
|
|
#include "WM_types.h"
|
2018-05-08 07:22:52 +02:00
|
|
|
#include "WM_message.h"
|
2018-05-23 08:20:46 +02:00
|
|
|
#include "WM_toolsystem.h"
|
2009-02-19 23:53:40 +00:00
|
|
|
|
|
|
|
#include "RNA_access.h"
|
|
|
|
#include "RNA_define.h"
|
|
|
|
|
|
|
|
#include "GPU_draw.h"
|
2016-11-08 11:06:30 -05:00
|
|
|
#include "GPU_immediate.h"
|
2018-06-27 19:07:23 -06:00
|
|
|
#include "GPU_state.h"
|
2009-02-19 23:53:40 +00:00
|
|
|
|
2014-07-21 12:02:05 +02:00
|
|
|
|
Color Management, Stage 2: Switch color pipeline to use OpenColorIO
Replace old color pipeline which was supporting linear/sRGB color spaces
only with OpenColorIO-based pipeline.
This introduces two configurable color spaces:
- Input color space for images and movie clips. This space is used to convert
images/movies from color space in which file is saved to Blender's linear
space (for float images, byte images are not internally converted, only input
space is stored for such images and used later).
This setting could be found in image/clip data block settings.
- Display color space which defines space in which particular display is working.
This settings could be found in scene's Color Management panel.
When render result is being displayed on the screen, apart from converting image
to display space, some additional conversions could happen.
This conversions are:
- View, which defines tone curve applying before display transformation.
These are different ways to view the image on the same display device.
For example it could be used to emulate film view on sRGB display.
- Exposure affects on image exposure before tone map is applied.
- Gamma is post-display gamma correction, could be used to match particular
display gamma.
- RGB curves are user-defined curves which are applying before display
transformation, could be used for different purposes.
All this settings by default are only applying on render result and does not
affect on other images. If some particular image needs to be affected by this
transformation, "View as Render" setting of image data block should be set to
truth. Movie clips are always affected by all display transformations.
This commit also introduces configurable color space in which sequencer is
working. This setting could be found in scene's Color Management panel and
it should be used if such stuff as grading needs to be done in color space
different from sRGB (i.e. when Film view on sRGB display is use, using VD16
space as sequencer's internal space would make grading working in space
which is close to the space using for display).
Some technical notes:
- Image buffer's float buffer is now always in linear space, even if it was
created from 16bit byte images.
- Space of byte buffer is stored in image buffer's rect_colorspace property.
- Profile of image buffer was removed since it's not longer meaningful.
- OpenGL and GLSL is supposed to always work in sRGB space. It is possible
to support other spaces, but it's quite large project which isn't so
much important.
- Legacy Color Management option disabled is emulated by using None display.
It could have some regressions, but there's no clear way to avoid them.
- If OpenColorIO is disabled on build time, it should make blender behaving
in the same way as previous release with color management enabled.
More details could be found at this page (more details would be added soon):
http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.64/Color_Management
--
Thanks to Xavier Thomas, Lukas Toene for initial work on OpenColorIO
integration and to Brecht van Lommel for some further development and code/
usecase review!
2012-09-15 10:05:07 +00:00
|
|
|
#include "IMB_colormanagement.h"
|
|
|
|
|
2009-02-19 23:53:40 +00:00
|
|
|
#include "paint_intern.h"
|
|
|
|
|
2019-04-10 00:06:53 +10:00
|
|
|
/* 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.
|
|
|
|
*/
|
2009-02-19 23:53:40 +00:00
|
|
|
static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0};
|
|
|
|
|
2013-03-08 04:00:06 +00:00
|
|
|
ImagePaintPartialRedraw *get_imapaintpartial(void)
|
|
|
|
{
|
2013-03-07 12:11:38 +00:00
|
|
|
return &imapaintpartial;
|
|
|
|
}
|
|
|
|
|
2013-03-08 04:00:06 +00:00
|
|
|
void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr)
|
|
|
|
{
|
2013-03-07 12:11:38 +00:00
|
|
|
imapaintpartial = *ippr;
|
|
|
|
}
|
|
|
|
|
2013-03-10 17:40:55 +00:00
|
|
|
/* Imagepaint Partial Redraw & Dirty Region */
|
2009-02-19 23:53:40 +00:00
|
|
|
|
2013-12-05 22:28:14 +02:00
|
|
|
void ED_imapaint_clear_partial_redraw(void)
|
2009-02-19 23:53:40 +00:00
|
|
|
{
|
2013-03-10 17:40:55 +00:00
|
|
|
memset(&imapaintpartial, 0, sizeof(imapaintpartial));
|
2009-02-19 23:53:40 +00:00
|
|
|
}
|
|
|
|
|
2013-04-30 06:07:42 +00:00
|
|
|
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) >> IMAPAINT_TILE_BITS);
|
|
|
|
*th = ((y + h - 1) >> IMAPAINT_TILE_BITS);
|
|
|
|
*tx = (x >> IMAPAINT_TILE_BITS);
|
|
|
|
*ty = (y >> IMAPAINT_TILE_BITS);
|
|
|
|
}
|
|
|
|
|
2015-04-30 13:52:25 +02:00
|
|
|
void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h, bool find_old)
|
2009-02-19 23:53:40 +00:00
|
|
|
{
|
2013-03-10 17:40:55 +00:00
|
|
|
ImBuf *tmpibuf = NULL;
|
2013-04-30 06:07:42 +00:00
|
|
|
int tilex, tiley, tilew, tileh, tx, ty;
|
|
|
|
int srcx = 0, srcy = 0;
|
2009-02-19 23:53:40 +00:00
|
|
|
|
2013-03-10 17:40:55 +00:00
|
|
|
IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h);
|
2009-02-19 23:53:40 +00:00
|
|
|
|
2013-03-10 17:40:55 +00:00
|
|
|
if (w == 0 || h == 0)
|
|
|
|
return;
|
2018-03-23 07:51:56 +01:00
|
|
|
|
2013-03-10 17:40:55 +00:00
|
|
|
if (!imapaintpartial.enabled) {
|
|
|
|
imapaintpartial.x1 = x;
|
|
|
|
imapaintpartial.y1 = y;
|
|
|
|
imapaintpartial.x2 = x + w;
|
|
|
|
imapaintpartial.y2 = y + h;
|
|
|
|
imapaintpartial.enabled = 1;
|
2009-02-19 23:53:40 +00:00
|
|
|
}
|
|
|
|
else {
|
2013-03-10 17:40:55 +00:00
|
|
|
imapaintpartial.x1 = min_ii(imapaintpartial.x1, x);
|
|
|
|
imapaintpartial.y1 = min_ii(imapaintpartial.y1, y);
|
|
|
|
imapaintpartial.x2 = max_ii(imapaintpartial.x2, x + w);
|
|
|
|
imapaintpartial.y2 = max_ii(imapaintpartial.y2, y + h);
|
2009-02-19 23:53:40 +00:00
|
|
|
}
|
|
|
|
|
2013-04-30 06:07:42 +00:00
|
|
|
imapaint_region_tiles(ibuf, x, y, w, h, &tilex, &tiley, &tilew, &tileh);
|
|
|
|
|
2018-03-19 14:17:59 +01:00
|
|
|
ListBase *undo_tiles = ED_image_undo_get_tiles();
|
|
|
|
|
2013-04-30 06:07:42 +00:00
|
|
|
for (ty = tiley; ty <= tileh; ty++)
|
|
|
|
for (tx = tilex; tx <= tilew; tx++)
|
2018-03-19 14:17:59 +01:00
|
|
|
image_undo_push_tile(undo_tiles, ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old);
|
2009-02-19 23:53:40 +00:00
|
|
|
|
2013-03-10 17:40:55 +00:00
|
|
|
ibuf->userflags |= IB_BITMAPDIRTY;
|
2018-03-23 07:51:56 +01:00
|
|
|
|
2013-03-10 17:40:55 +00:00
|
|
|
if (tmpibuf)
|
|
|
|
IMB_freeImBuf(tmpibuf);
|
2009-02-19 23:53:40 +00:00
|
|
|
}
|
|
|
|
|
2013-03-10 17:40:55 +00:00
|
|
|
void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint)
|
2009-02-19 23:53:40 +00:00
|
|
|
{
|
2013-02-11 13:24:35 +00:00
|
|
|
if (imapaintpartial.x1 != imapaintpartial.x2 &&
|
|
|
|
imapaintpartial.y1 != imapaintpartial.y2)
|
|
|
|
{
|
2018-07-02 18:45:26 +02:00
|
|
|
IMB_partial_display_buffer_update_delayed(
|
|
|
|
ibuf, imapaintpartial.x1, imapaintpartial.y1,
|
|
|
|
imapaintpartial.x2, imapaintpartial.y2);
|
2009-02-19 23:53:40 +00:00
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2013-03-10 17:40:55 +00:00
|
|
|
if (ibuf->mipmap[0])
|
|
|
|
ibuf->userflags |= IB_MIPMAP_INVALID;
|
2009-02-19 23:53:40 +00:00
|
|
|
|
2013-03-10 17:40:55 +00:00
|
|
|
/* todo: should set_tpage create ->rect? */
|
|
|
|
if (texpaint || (sima && sima->lock)) {
|
|
|
|
int w = imapaintpartial.x2 - imapaintpartial.x1;
|
|
|
|
int h = imapaintpartial.y2 - imapaintpartial.y1;
|
2016-05-05 18:52:11 +10:00
|
|
|
if (w && h) {
|
|
|
|
/* Testing with partial update in uv editor too */
|
|
|
|
GPU_paint_update_image(image, (sima ? &sima->iuser : NULL), imapaintpartial.x1, imapaintpartial.y1, w, h);
|
|
|
|
}
|
2013-03-10 17:40:55 +00:00
|
|
|
}
|
2009-02-19 23:53:40 +00:00
|
|
|
}
|
|
|
|
|
2014-08-27 15:07:57 +02:00
|
|
|
/* paint blur kernels. Projective painting enforces use of a 2x2 kernel due to lagging */
|
|
|
|
BlurKernel *paint_new_blur_kernel(Brush *br, bool proj)
|
2014-07-21 12:02:05 +02:00
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
BlurKernel *kernel = MEM_mallocN(sizeof(BlurKernel), "blur kernel");
|
2014-08-27 15:07:57 +02:00
|
|
|
float radius;
|
|
|
|
int side;
|
2017-10-17 13:43:10 +11:00
|
|
|
eBlurKernelType type = br->blur_mode;
|
2014-07-21 12:02:05 +02:00
|
|
|
|
2014-08-27 15:07:57 +02:00
|
|
|
if (proj) {
|
|
|
|
radius = 0.5f;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2014-08-27 15:07:57 +02:00
|
|
|
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 {
|
2014-09-26 14:13:32 +02:00
|
|
|
if (br->blur_kernel_radius <= 0)
|
|
|
|
br->blur_kernel_radius = 1;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2014-09-26 14:13:32 +02:00
|
|
|
radius = br->blur_kernel_radius;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2014-08-27 15:07:57 +02:00
|
|
|
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;
|
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2014-07-21 12:02:05 +02:00
|
|
|
switch (type) {
|
|
|
|
case KERNEL_BOX:
|
|
|
|
for (i = 0; i < kernel->side_squared; i++)
|
|
|
|
kernel->wdata[i] = 1.0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KERNEL_GAUSSIAN:
|
|
|
|
{
|
2018-06-04 09:31:30 +02:00
|
|
|
/* at 3.0 standard deviations distance, kernel is about zero */
|
|
|
|
float standard_dev = radius / 3.0f;
|
|
|
|
|
2014-07-21 12:02:05 +02:00
|
|
|
/* make the necessary adjustment to the value for use in the normal distribution formula */
|
2014-09-26 14:13:32 +02:00
|
|
|
standard_dev = -standard_dev * standard_dev * 2;
|
2014-07-21 12:02:05 +02:00
|
|
|
|
2014-08-27 15:07:57 +02:00
|
|
|
for (i = 0; i < side; i++) {
|
|
|
|
for (j = 0; j < side; j++) {
|
|
|
|
float idist = radius - i;
|
|
|
|
float jdist = radius - j;
|
2014-07-21 12:02:05 +02:00
|
|
|
float value = exp((idist * idist + jdist * jdist) / standard_dev);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2014-08-27 15:07:57 +02:00
|
|
|
kernel->wdata[i + j * side] = value;
|
2014-07-21 12:02:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2009-02-19 23:53:40 +00:00
|
|
|
/************************ image paint poll ************************/
|
|
|
|
|
|
|
|
static Brush *image_paint_brush(bContext *C)
|
|
|
|
{
|
2012-03-28 03:47:33 +00:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
ToolSettings *settings = scene->toolsettings;
|
2009-02-19 23:53:40 +00:00
|
|
|
|
Paint refactoring commit, non-disruptive (in theory :p)
* Fix precision overflow issue with overlay previews,
* Expose alpha mask mapping to UI (still not functional but coming soon).
* More overlay refactoring:
Overlay now does minimal checking for texture refresh.
Instead, we now have invalidation flags to set an aspect of the brush
overlay as invalid. This is necessary because this way we will be able to
separate and preview different brush attributes on the overlays, using
different textures:
These attributes/aspects are:
Primary texture (main texture for sculpt, vertex, imapaint)
Secondary texture (mask/alpha texture for imapaint)
Cursor texture (cursor texture. It involves brush strength and curves)
Modified the relevant RNA property update functions and C update callback
functions to call the relevant cursor invalidation functions instead
of checking every frame for multiple properties.
Properties that affect this are:
Image changes, if image is used by current brush,
Texture slot changes, similarly
Curve changes,
Object mode change invalidates the cursor
Paint tool change invalidates the cursor.
These changes give slightly more invalidation cases than simply
comparing the relevant properties each frame, but these do not occur in
performance critical moments and it's a much more elegant system than
adding more variables to check per frame each time we add something on
the system.
2013-04-12 17:21:31 +00:00
|
|
|
return BKE_paint_brush(&settings->imapaint.paint);
|
2009-02-19 23:53:40 +00:00
|
|
|
}
|
|
|
|
|
2018-07-02 12:03:56 +02:00
|
|
|
static bool image_paint_poll_ex(bContext *C, bool check_tool)
|
2009-02-19 23:53:40 +00:00
|
|
|
{
|
2014-09-10 23:02:31 +10:00
|
|
|
Object *obact;
|
2009-08-16 01:25:53 +00:00
|
|
|
|
2018-04-05 18:20:27 +02:00
|
|
|
if (!image_paint_brush(C))
|
2009-02-19 23:53:40 +00:00
|
|
|
return 0;
|
2018-02-09 22:14:17 +11:00
|
|
|
|
2014-09-10 23:02:31 +10:00
|
|
|
obact = CTX_data_active_object(C);
|
2018-04-05 18:20:27 +02:00
|
|
|
if ((obact && obact->mode & OB_MODE_TEXTURE_PAINT) && CTX_wm_region_view3d(C)) {
|
2018-05-01 11:42:25 +02:00
|
|
|
if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) {
|
2018-05-01 11:22:12 +02:00
|
|
|
return 1;
|
|
|
|
}
|
2009-02-19 23:53:40 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-03-28 03:47:33 +00:00
|
|
|
SpaceImage *sima = CTX_wm_space_image(C);
|
2009-02-19 23:53:40 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (sima) {
|
2012-03-28 03:47:33 +00:00
|
|
|
ARegion *ar = CTX_wm_region(C);
|
2009-02-19 23:53:40 +00:00
|
|
|
|
2012-07-25 11:25:10 +00:00
|
|
|
if ((sima->mode == SI_MODE_PAINT) && ar->regiontype == RGN_TYPE_WINDOW) {
|
2009-02-19 23:53:40 +00:00
|
|
|
return 1;
|
2012-07-25 11:25:10 +00:00
|
|
|
}
|
2009-02-19 23:53:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-07-02 12:03:56 +02:00
|
|
|
static bool image_paint_poll(bContext *C)
|
2018-05-01 11:42:25 +02:00
|
|
|
{
|
|
|
|
return image_paint_poll_ex(C, true);
|
|
|
|
}
|
|
|
|
|
2019-01-04 08:02:17 +11:00
|
|
|
static bool image_paint_poll_ignore_tool(bContext *C)
|
2018-05-01 11:42:25 +02:00
|
|
|
{
|
|
|
|
return image_paint_poll_ex(C, false);
|
|
|
|
}
|
|
|
|
|
2018-07-02 11:47:00 +02:00
|
|
|
static bool image_paint_2d_clone_poll(bContext *C)
|
2009-02-19 23:53:40 +00:00
|
|
|
{
|
2012-03-28 03:47:33 +00:00
|
|
|
Brush *brush = image_paint_brush(C);
|
2009-02-19 23:53:40 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!CTX_wm_region_view3d(C) && image_paint_poll(C))
|
|
|
|
if (brush && (brush->imagepaint_tool == PAINT_TOOL_CLONE))
|
|
|
|
if (brush->clone.image)
|
2009-02-19 23:53:40 +00:00
|
|
|
return 1;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-02-19 23:53:40 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************ paint operator ************************/
|
2017-10-17 13:43:10 +11:00
|
|
|
typedef enum eTexPaintMode {
|
2009-02-19 23:53:40 +00:00
|
|
|
PAINT_MODE_2D,
|
|
|
|
PAINT_MODE_3D_PROJECT
|
2017-10-17 13:43:10 +11:00
|
|
|
} eTexPaintMode;
|
2009-02-19 23:53:40 +00:00
|
|
|
|
|
|
|
typedef struct PaintOperation {
|
2017-10-17 13:43:10 +11:00
|
|
|
eTexPaintMode mode;
|
2009-02-19 23:53:40 +00:00
|
|
|
|
2013-03-10 17:40:55 +00:00
|
|
|
void *custom_paint;
|
2009-02-19 23:53:40 +00:00
|
|
|
|
2013-05-15 11:16:01 +00:00
|
|
|
float prevmouse[2];
|
2014-07-21 12:02:05 +02:00
|
|
|
float startmouse[2];
|
2009-02-19 23:53:40 +00:00
|
|
|
double starttime;
|
|
|
|
|
2014-07-21 12:02:05 +02:00
|
|
|
void *cursor;
|
2009-02-19 23:53:40 +00:00
|
|
|
ViewContext vc;
|
|
|
|
} PaintOperation;
|
|
|
|
|
2014-07-21 12:02:05 +02:00
|
|
|
bool paint_use_opacity_masking(Brush *brush)
|
|
|
|
{
|
2018-07-02 18:45:26 +02:00
|
|
|
return ((brush->flag & BRUSH_AIRBRUSH) ||
|
|
|
|
(brush->flag & BRUSH_DRAG_DOT) ||
|
|
|
|
(brush->flag & BRUSH_ANCHORED) ||
|
|
|
|
(brush->imagepaint_tool == PAINT_TOOL_SMEAR) ||
|
|
|
|
(brush->imagepaint_tool == 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);
|
2014-07-21 12:02:05 +02:00
|
|
|
}
|
|
|
|
|
2018-03-23 11:28:25 +01:00
|
|
|
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)
|
2014-07-21 12:02:05 +02:00
|
|
|
{
|
|
|
|
if (invert)
|
|
|
|
copy_v3_v3(color, BKE_brush_secondary_color_get(scene, br));
|
|
|
|
else {
|
|
|
|
if (br->flag & BRUSH_USE_GRADIENT) {
|
2015-01-07 23:01:42 +01:00
|
|
|
float color_gr[4];
|
2014-07-21 12:02:05 +02:00
|
|
|
switch (br->gradient_stroke_mode) {
|
|
|
|
case BRUSH_GRADIENT_PRESSURE:
|
2017-12-07 15:52:59 +11:00
|
|
|
BKE_colorband_evaluate(br->gradient, pressure, color_gr);
|
2014-07-21 12:02:05 +02:00
|
|
|
break;
|
|
|
|
case BRUSH_GRADIENT_SPACING_REPEAT:
|
|
|
|
{
|
|
|
|
float coord = fmod(distance / br->gradient_spacing, 1.0);
|
2017-12-07 15:52:59 +11:00
|
|
|
BKE_colorband_evaluate(br->gradient, coord, color_gr);
|
2014-07-21 12:02:05 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case BRUSH_GRADIENT_SPACING_CLAMP:
|
|
|
|
{
|
2017-12-07 15:52:59 +11:00
|
|
|
BKE_colorband_evaluate(br->gradient, distance / br->gradient_spacing, color_gr);
|
2014-07-21 12:02:05 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2015-01-07 23:01:42 +01:00
|
|
|
copy_v3_v3(color, color_gr);
|
2014-07-21 12:02:05 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
copy_v3_v3(color, BKE_brush_color_get(scene, br));
|
|
|
|
}
|
|
|
|
if (color_correction)
|
|
|
|
IMB_colormanagement_display_to_scene_linear_v3(color, display);
|
|
|
|
}
|
|
|
|
|
2013-03-10 17:40:55 +00:00
|
|
|
void paint_brush_init_tex(Brush *brush)
|
2009-02-19 23:53:40 +00:00
|
|
|
{
|
2013-03-10 17:40:55 +00:00
|
|
|
/* init mtex nodes */
|
|
|
|
if (brush) {
|
|
|
|
MTex *mtex = &brush->mtex;
|
2019-01-15 23:24:20 +11:00
|
|
|
if (mtex->tex && mtex->tex->nodetree) {
|
|
|
|
/* has internal flag to detect it only does it once */
|
|
|
|
ntreeTexBeginExecTree(mtex->tex->nodetree);
|
|
|
|
}
|
2013-03-25 01:00:16 +00:00
|
|
|
mtex = &brush->mask_mtex;
|
2019-01-15 23:24:20 +11:00
|
|
|
if (mtex->tex && mtex->tex->nodetree) {
|
2013-03-25 01:00:16 +00:00
|
|
|
ntreeTexBeginExecTree(mtex->tex->nodetree);
|
2019-01-15 23:24:20 +11:00
|
|
|
}
|
2009-02-19 23:53:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-10 17:40:55 +00:00
|
|
|
void paint_brush_exit_tex(Brush *brush)
|
2009-02-19 23:53:40 +00:00
|
|
|
{
|
2013-03-10 17:40:55 +00:00
|
|
|
if (brush) {
|
|
|
|
MTex *mtex = &brush->mtex;
|
|
|
|
if (mtex->tex && mtex->tex->nodetree)
|
2013-03-18 16:34:57 +00:00
|
|
|
ntreeTexEndExecTree(mtex->tex->nodetree->execdata);
|
2013-03-25 01:00:16 +00:00
|
|
|
mtex = &brush->mask_mtex;
|
|
|
|
if (mtex->tex && mtex->tex->nodetree)
|
|
|
|
ntreeTexEndExecTree(mtex->tex->nodetree->execdata);
|
2013-02-14 01:30:13 +00:00
|
|
|
}
|
2013-03-10 17:40:55 +00:00
|
|
|
}
|
2010-03-14 22:43:44 +00:00
|
|
|
|
2014-07-21 12:02:05 +02:00
|
|
|
static void gradient_draw_line(bContext *UNUSED(C), int x, int y, void *customdata)
|
|
|
|
{
|
|
|
|
PaintOperation *pop = (PaintOperation *)customdata;
|
|
|
|
|
|
|
|
if (pop) {
|
2018-06-27 19:07:23 -06:00
|
|
|
GPU_line_smooth(true);
|
|
|
|
GPU_blend(true);
|
2014-07-21 12:02:05 +02:00
|
|
|
|
2018-07-18 00:12:21 +02:00
|
|
|
GPUVertFormat *format = immVertexFormat();
|
|
|
|
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
|
2016-11-08 11:06:30 -05:00
|
|
|
|
2019-04-16 13:36:44 +02:00
|
|
|
ARegion *ar = pop->vc.ar;
|
|
|
|
|
2016-11-08 11:06:30 -05:00
|
|
|
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
|
|
|
|
|
2018-06-27 19:07:23 -06:00
|
|
|
GPU_line_width(4.0);
|
2016-11-08 11:06:30 -05:00
|
|
|
immUniformColor4ub(0, 0, 0, 255);
|
|
|
|
|
2018-07-18 00:12:21 +02:00
|
|
|
immBegin(GPU_PRIM_LINES, 2);
|
2016-11-08 11:06:30 -05:00
|
|
|
immVertex2i(pos, x, y);
|
2019-04-16 13:36:44 +02:00
|
|
|
immVertex2i(pos, pop->startmouse[0] + ar->winrct.xmin, pop->startmouse[1] + ar->winrct.ymin);
|
2016-11-08 11:06:30 -05:00
|
|
|
immEnd();
|
|
|
|
|
2018-06-27 19:07:23 -06:00
|
|
|
GPU_line_width(2.0);
|
2016-11-08 11:06:30 -05:00
|
|
|
immUniformColor4ub(255, 255, 255, 255);
|
|
|
|
|
2018-07-18 00:12:21 +02:00
|
|
|
immBegin(GPU_PRIM_LINES, 2);
|
2016-11-08 11:06:30 -05:00
|
|
|
immVertex2i(pos, x, y);
|
2019-04-16 13:36:44 +02:00
|
|
|
immVertex2i(pos, pop->startmouse[0] + ar->winrct.xmin, pop->startmouse[1] + ar->winrct.ymin);
|
2016-11-08 11:06:30 -05:00
|
|
|
immEnd();
|
|
|
|
|
|
|
|
immUnbindProgram();
|
2014-07-21 12:02:05 +02:00
|
|
|
|
2018-06-27 19:07:23 -06:00
|
|
|
GPU_blend(false);
|
|
|
|
GPU_line_smooth(false);
|
2014-07-21 12:02:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-05 10:26:23 +00:00
|
|
|
|
2014-07-21 12:02:05 +02:00
|
|
|
static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const float mouse[2])
|
2009-02-19 23:53:40 +00:00
|
|
|
{
|
2012-03-28 03:47:33 +00:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
ToolSettings *settings = scene->toolsettings;
|
|
|
|
PaintOperation *pop = MEM_callocN(sizeof(PaintOperation), "PaintOperation"); /* caller frees */
|
2014-07-21 12:02:05 +02:00
|
|
|
Brush *brush = BKE_paint_brush(&settings->imapaint.paint);
|
2013-03-17 03:08:46 +00:00
|
|
|
int mode = RNA_enum_get(op->ptr, "mode");
|
2018-03-08 17:30:24 +11:00
|
|
|
ED_view3d_viewcontext_init(C, &pop->vc);
|
2013-03-10 17:40:55 +00:00
|
|
|
|
2014-07-21 12:02:05 +02:00
|
|
|
copy_v2_v2(pop->prevmouse, mouse);
|
|
|
|
copy_v2_v2(pop->startmouse, mouse);
|
|
|
|
|
2009-02-19 23:53:40 +00:00
|
|
|
/* initialize from context */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (CTX_wm_region_view3d(C)) {
|
2017-11-23 13:51:49 -02:00
|
|
|
ViewLayer *view_layer = CTX_data_view_layer(C);
|
|
|
|
Object *ob = OBACT(view_layer);
|
2014-10-06 15:12:06 +02:00
|
|
|
bool uvs, mat, tex, stencil;
|
|
|
|
if (!BKE_paint_proj_mesh_data_check(scene, ob, &uvs, &mat, &tex, &stencil)) {
|
|
|
|
BKE_paint_data_warning(op->reports, uvs, mat, tex, stencil);
|
|
|
|
MEM_freeN(pop);
|
|
|
|
WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
|
2018-06-04 09:31:30 +02:00
|
|
|
return NULL;
|
2014-10-06 15:12:06 +02:00
|
|
|
}
|
2013-03-06 19:54:43 +00:00
|
|
|
pop->mode = PAINT_MODE_3D_PROJECT;
|
2014-07-21 12:02:05 +02:00
|
|
|
pop->custom_paint = paint_proj_new_stroke(C, ob, mouse, mode);
|
2009-02-19 23:53:40 +00:00
|
|
|
}
|
|
|
|
else {
|
2013-03-10 17:40:55 +00:00
|
|
|
pop->mode = PAINT_MODE_2D;
|
2014-07-21 12:02:05 +02:00
|
|
|
pop->custom_paint = paint_2d_new_stroke(C, op, mode);
|
2009-02-19 23:53:40 +00:00
|
|
|
}
|
|
|
|
|
2013-03-10 17:40:55 +00:00
|
|
|
if (!pop->custom_paint) {
|
|
|
|
MEM_freeN(pop);
|
|
|
|
return NULL;
|
2009-02-19 23:53:40 +00:00
|
|
|
}
|
2013-01-04 02:54:38 +00:00
|
|
|
|
2014-10-06 15:12:06 +02:00
|
|
|
if ((brush->imagepaint_tool == PAINT_TOOL_FILL) && (brush->flag & BRUSH_USE_GRADIENT)) {
|
2018-10-25 16:06:47 +11:00
|
|
|
pop->cursor = WM_paint_cursor_activate(
|
|
|
|
CTX_wm_manager(C),
|
|
|
|
SPACE_TYPE_ANY, RGN_TYPE_ANY,
|
|
|
|
image_paint_poll, gradient_draw_line,
|
|
|
|
pop);
|
2014-10-06 15:12:06 +02:00
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-02-19 23:53:40 +00:00
|
|
|
settings->imapaint.flag |= IMAGEPAINT_DRAWING;
|
2019-02-05 14:24:11 +11:00
|
|
|
ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D);
|
2013-01-17 04:24:22 +00:00
|
|
|
|
2013-03-10 17:40:55 +00:00
|
|
|
return pop;
|
2009-02-19 23:53:40 +00:00
|
|
|
}
|
|
|
|
|
2013-03-10 17:40:55 +00:00
|
|
|
static void paint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
|
2009-02-19 23:53:40 +00:00
|
|
|
{
|
2013-03-10 17:40:55 +00:00
|
|
|
PaintOperation *pop = paint_stroke_mode_data(stroke);
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
2014-07-21 12:02:05 +02:00
|
|
|
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;
|
2013-03-10 17:40:55 +00:00
|
|
|
|
|
|
|
/* initial brush values. Maybe it should be considered moving these to stroke system */
|
|
|
|
float startalpha = BKE_brush_alpha_get(scene, brush);
|
|
|
|
|
2013-05-15 11:16:01 +00:00
|
|
|
float mouse[2];
|
2009-02-19 23:53:40 +00:00
|
|
|
float pressure;
|
2014-07-21 12:02:05 +02:00
|
|
|
float size;
|
|
|
|
float distance = paint_stroke_distance_get(stroke);
|
2013-05-15 14:37:05 +00:00
|
|
|
int eraser;
|
2009-02-19 23:53:40 +00:00
|
|
|
|
2013-05-15 11:16:01 +00:00
|
|
|
RNA_float_get_array(itemptr, "mouse", mouse);
|
2012-03-28 03:47:33 +00:00
|
|
|
pressure = RNA_float_get(itemptr, "pressure");
|
2013-03-10 17:40:55 +00:00
|
|
|
eraser = RNA_boolean_get(itemptr, "pen_flip");
|
2014-07-21 12:02:05 +02:00
|
|
|
size = max_ff(1.0f, 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;
|
|
|
|
}
|
2009-02-19 23:53:40 +00:00
|
|
|
|
2013-03-10 17:40:55 +00:00
|
|
|
if (BKE_brush_use_alpha_pressure(scene, brush))
|
2014-07-21 12:02:05 +02:00
|
|
|
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)) {
|
2018-03-19 14:17:59 +01:00
|
|
|
UndoStack *ustack = CTX_wm_manager(C)->undo_stack;
|
|
|
|
ED_image_undo_restore(ustack->step_init);
|
2014-07-21 12:02:05 +02:00
|
|
|
}
|
2009-02-19 23:53:40 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (pop->mode == PAINT_MODE_3D_PROJECT) {
|
2014-08-12 14:20:06 +02:00
|
|
|
paint_proj_stroke(C, pop->custom_paint, pop->prevmouse, mouse, eraser, pressure, distance, size);
|
2009-02-19 23:53:40 +00:00
|
|
|
}
|
2012-10-21 05:46:41 +00:00
|
|
|
else {
|
2014-07-21 12:02:05 +02:00
|
|
|
paint_2d_stroke(pop->custom_paint, pop->prevmouse, mouse, eraser, pressure, distance, size);
|
2009-02-19 23:53:40 +00:00
|
|
|
}
|
|
|
|
|
2014-07-21 12:02:05 +02:00
|
|
|
copy_v2_v2(pop->prevmouse, mouse);
|
2009-02-19 23:53:40 +00:00
|
|
|
|
2013-03-10 17:40:55 +00:00
|
|
|
/* restore brush values */
|
|
|
|
BKE_brush_alpha_set(scene, brush, startalpha);
|
2013-05-15 14:37:05 +00:00
|
|
|
}
|
2013-03-10 17:40:55 +00:00
|
|
|
|
2013-05-15 14:37:05 +00:00
|
|
|
static void paint_stroke_redraw(const bContext *C, struct PaintStroke *stroke, bool final)
|
|
|
|
{
|
|
|
|
PaintOperation *pop = paint_stroke_mode_data(stroke);
|
2013-03-10 17:40:55 +00:00
|
|
|
|
2013-05-15 14:37:05 +00:00
|
|
|
if (pop->mode == PAINT_MODE_3D_PROJECT) {
|
|
|
|
paint_proj_redraw(C, pop->custom_paint, final);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
paint_2d_redraw(C, pop->custom_paint, final);
|
|
|
|
}
|
2011-03-03 18:53:07 +00:00
|
|
|
}
|
|
|
|
|
2013-03-10 17:40:55 +00:00
|
|
|
static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke)
|
2009-02-19 23:53:40 +00:00
|
|
|
{
|
2012-03-28 03:47:33 +00:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
2014-07-21 12:02:05 +02:00
|
|
|
ToolSettings *toolsettings = scene->toolsettings;
|
2013-03-10 17:40:55 +00:00
|
|
|
PaintOperation *pop = paint_stroke_mode_data(stroke);
|
2014-07-21 12:02:05 +02:00
|
|
|
Brush *brush = BKE_paint_brush(&toolsettings->imapaint.paint);
|
2009-02-19 23:53:40 +00:00
|
|
|
|
2014-07-21 12:02:05 +02:00
|
|
|
toolsettings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
|
2009-02-19 23:53:40 +00:00
|
|
|
|
2014-07-21 12:02:05 +02:00
|
|
|
if (brush->imagepaint_tool == PAINT_TOOL_FILL) {
|
|
|
|
if (brush->flag & BRUSH_USE_GRADIENT) {
|
|
|
|
if (pop->mode == PAINT_MODE_2D) {
|
|
|
|
paint_2d_gradient_fill(C, brush, pop->startmouse, pop->prevmouse, pop->custom_paint);
|
|
|
|
}
|
|
|
|
else {
|
2018-07-02 18:45:26 +02:00
|
|
|
paint_proj_stroke(
|
|
|
|
C, pop->custom_paint, pop->startmouse, pop->prevmouse, paint_stroke_flipped(stroke),
|
|
|
|
1.0, 0.0, BKE_brush_size_get(scene, brush));
|
2014-07-21 12:02:05 +02:00
|
|
|
/* two redraws, one for GPU update, one for notification */
|
|
|
|
paint_proj_redraw(C, pop->custom_paint, false);
|
|
|
|
paint_proj_redraw(C, pop->custom_paint, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (pop->mode == PAINT_MODE_2D) {
|
|
|
|
float color[3];
|
2019-03-08 15:53:38 +01:00
|
|
|
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));
|
|
|
|
}
|
2014-07-21 12:02:05 +02:00
|
|
|
paint_2d_bucket_fill(C, color, brush, pop->prevmouse, pop->custom_paint);
|
|
|
|
}
|
|
|
|
else {
|
2018-07-02 18:45:26 +02:00
|
|
|
paint_proj_stroke(
|
|
|
|
C, pop->custom_paint, pop->startmouse, pop->prevmouse, paint_stroke_flipped(stroke),
|
|
|
|
1.0, 0.0, BKE_brush_size_get(scene, brush));
|
2014-07-21 12:02:05 +02:00
|
|
|
/* two redraws, one for GPU update, one for notification */
|
|
|
|
paint_proj_redraw(C, pop->custom_paint, false);
|
|
|
|
paint_proj_redraw(C, pop->custom_paint, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (pop->mode == PAINT_MODE_3D_PROJECT) {
|
2013-03-10 17:40:55 +00:00
|
|
|
paint_proj_stroke_done(pop->custom_paint);
|
2008-10-31 05:51:16 +00:00
|
|
|
}
|
2012-03-28 01:06:43 +00:00
|
|
|
else {
|
2013-03-10 17:40:55 +00:00
|
|
|
paint_2d_stroke_done(pop->custom_paint);
|
2012-03-28 01:06:43 +00:00
|
|
|
}
|
2013-03-06 19:54:43 +00:00
|
|
|
|
2014-07-21 12:02:05 +02:00
|
|
|
if (pop->cursor) {
|
|
|
|
WM_paint_cursor_end(CTX_wm_manager(C), pop->cursor);
|
|
|
|
}
|
|
|
|
|
2018-03-23 07:51:56 +01:00
|
|
|
ED_image_undo_push_end();
|
2013-03-06 19:54:43 +00:00
|
|
|
|
2013-06-06 06:02:46 +00:00
|
|
|
/* duplicate warning, see texpaint_init */
|
|
|
|
#if 0
|
2012-03-24 06:38:07 +00:00
|
|
|
if (pop->s.warnmultifile)
|
2009-02-19 23:53:40 +00:00
|
|
|
BKE_reportf(op->reports, RPT_WARNING, "Image requires 4 color channels to paint: %s", pop->s.warnmultifile);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (pop->s.warnpackedfile)
|
2009-02-19 23:53:40 +00:00
|
|
|
BKE_reportf(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted: %s", pop->s.warnpackedfile);
|
2013-06-06 06:02:46 +00:00
|
|
|
#endif
|
2009-02-19 23:53:40 +00:00
|
|
|
MEM_freeN(pop);
|
|
|
|
}
|
|
|
|
|
2014-07-21 12:02:05 +02:00
|
|
|
static bool paint_stroke_test_start(bContext *C, wmOperator *op, const float mouse[2])
|
2009-02-19 23:53:40 +00:00
|
|
|
{
|
|
|
|
PaintOperation *pop;
|
|
|
|
|
2013-05-15 22:55:30 +00:00
|
|
|
/* TODO Should avoid putting this here. Instead, last position should be requested
|
|
|
|
* from stroke system. */
|
|
|
|
|
|
|
|
if (!(pop = texture_paint_init(C, op, mouse))) {
|
2014-07-21 12:02:05 +02:00
|
|
|
return false;
|
2009-02-19 23:53:40 +00:00
|
|
|
}
|
2013-01-17 04:24:22 +00:00
|
|
|
|
2014-07-21 12:02:05 +02:00
|
|
|
paint_stroke_set_mode_data(op->customdata, pop);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int paint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|
|
|
{
|
|
|
|
int retval;
|
|
|
|
|
2018-07-02 18:45:26 +02:00
|
|
|
op->customdata = paint_stroke_new(
|
|
|
|
C, op, NULL, paint_stroke_test_start,
|
|
|
|
paint_stroke_update_step,
|
|
|
|
paint_stroke_redraw,
|
|
|
|
paint_stroke_done, event->type);
|
2014-07-21 12:02:05 +02:00
|
|
|
|
|
|
|
if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
|
|
|
|
paint_stroke_data_free(op);
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
2013-03-10 17:40:55 +00:00
|
|
|
/* add modal handler */
|
2009-10-22 23:22:05 +00:00
|
|
|
WM_event_add_modal_handler(C, op);
|
2009-02-19 23:53:40 +00:00
|
|
|
|
2013-03-10 17:40:55 +00:00
|
|
|
OPERATOR_RETVAL_CHECK(retval);
|
|
|
|
BLI_assert(retval == OPERATOR_RUNNING_MODAL);
|
2009-02-19 23:53:40 +00:00
|
|
|
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
|
|
}
|
|
|
|
|
2013-05-15 22:55:30 +00:00
|
|
|
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);
|
|
|
|
|
2018-07-02 18:45:26 +02:00
|
|
|
op->customdata = paint_stroke_new(
|
|
|
|
C, op, NULL, paint_stroke_test_start,
|
|
|
|
paint_stroke_update_step,
|
|
|
|
paint_stroke_redraw,
|
|
|
|
paint_stroke_done, 0);
|
2013-05-15 22:55:30 +00:00
|
|
|
/* frees op->customdata */
|
2016-02-24 00:31:46 +11:00
|
|
|
return paint_stroke_exec(C, op);
|
2013-05-15 22:55:30 +00:00
|
|
|
}
|
2009-02-19 23:53:40 +00:00
|
|
|
|
|
|
|
void PAINT_OT_image_paint(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Image Paint";
|
|
|
|
ot->idname = "PAINT_OT_image_paint";
|
2012-05-05 17:10:51 +00:00
|
|
|
ot->description = "Paint a stroke into the image";
|
2013-03-10 17:40:55 +00:00
|
|
|
|
2009-02-19 23:53:40 +00:00
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->invoke = paint_invoke;
|
2013-03-10 17:40:55 +00:00
|
|
|
ot->modal = paint_stroke_modal;
|
2013-05-15 22:55:30 +00:00
|
|
|
ot->exec = paint_exec;
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->poll = image_paint_poll;
|
2013-03-10 17:40:55 +00:00
|
|
|
ot->cancel = paint_stroke_cancel;
|
2009-02-19 23:53:40 +00:00
|
|
|
|
|
|
|
/* flags */
|
2014-03-13 22:35:26 +02:00
|
|
|
ot->flag = OPTYPE_BLOCKING;
|
2009-02-19 23:53:40 +00:00
|
|
|
|
2014-09-03 14:00:34 +02:00
|
|
|
paint_stroke_operator_properties(ot);
|
2009-02-19 23:53:40 +00:00
|
|
|
}
|
|
|
|
|
2013-03-10 17:40:55 +00:00
|
|
|
|
2013-03-10 18:46:31 +00:00
|
|
|
int get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy)
|
2009-02-22 19:31:25 +00:00
|
|
|
{
|
2012-03-28 03:47:33 +00:00
|
|
|
RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
2009-02-22 19:31:25 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!rv3d) {
|
2012-03-28 03:47:33 +00:00
|
|
|
SpaceImage *sima = CTX_wm_space_image(C);
|
2009-02-22 19:31:25 +00:00
|
|
|
|
2012-10-29 19:47:26 +00:00
|
|
|
if (sima->mode == SI_MODE_PAINT) {
|
2014-07-21 12:02:05 +02:00
|
|
|
ARegion *ar = CTX_wm_region(C);
|
2012-10-29 19:47:26 +00:00
|
|
|
ED_space_image_get_zoom(sima, ar, zoomx, zoomy);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
2009-02-22 19:31:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
*zoomx = *zoomy = 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************ cursor drawing *******************************/
|
|
|
|
|
|
|
|
static void toggle_paint_cursor(bContext *C, int enable)
|
|
|
|
{
|
2012-03-28 03:47:33 +00:00
|
|
|
wmWindowManager *wm = CTX_wm_manager(C);
|
2012-01-17 18:01:16 +00:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
2012-03-28 03:47:33 +00:00
|
|
|
ToolSettings *settings = scene->toolsettings;
|
2009-02-22 19:31:25 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (settings->imapaint.paintcursor && !enable) {
|
2012-01-17 18:01:16 +00:00
|
|
|
WM_paint_cursor_end(wm, settings->imapaint.paintcursor);
|
2009-02-22 19:31:25 +00:00
|
|
|
settings->imapaint.paintcursor = NULL;
|
2013-10-09 16:00:15 +00:00
|
|
|
paint_cursor_delete_textures();
|
2009-02-22 19:31:25 +00:00
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (enable)
|
2013-03-29 14:02:28 +00:00
|
|
|
paint_cursor_start(C, image_paint_poll);
|
2009-02-22 19:31:25 +00:00
|
|
|
}
|
|
|
|
|
2010-10-20 00:42:19 +00:00
|
|
|
/* enable the paint cursor if it isn't already.
|
2012-03-03 16:31:46 +00:00
|
|
|
*
|
|
|
|
* purpose is to make sure the paint cursor is shown if paint
|
|
|
|
* mode is enabled in the image editor. the paint poll will
|
|
|
|
* ensure that the cursor is hidden when not in paint mode */
|
2018-06-11 11:05:37 +02:00
|
|
|
void ED_space_image_paint_update(Main *bmain, wmWindowManager *wm, Scene *scene)
|
2010-10-20 00:42:19 +00:00
|
|
|
{
|
2015-08-31 21:37:38 +03:00
|
|
|
ToolSettings *settings = scene->toolsettings;
|
2010-10-20 00:42:19 +00:00
|
|
|
ImagePaintSettings *imapaint = &settings->imapaint;
|
2014-04-11 11:25:41 +10:00
|
|
|
bool enabled = false;
|
2010-10-20 00:42:19 +00:00
|
|
|
|
Main Workspace Integration
This commit does the main integration of workspaces, which is a design we agreed on during the 2.8 UI workshop (see https://wiki.blender.org/index.php/Dev:2.8/UI/Workshop_Writeup)
Workspaces should generally be stable, I'm not aware of any remaining bugs (or I've forgotten them :) ). If you find any, let me know!
(Exception: mode switching button might get out of sync with actual mode in some cases, would consider that a limitation/ToDo. Needs to be resolved at some point.)
== Main Changes/Features
* Introduces the new Workspaces as data-blocks.
* Allow storing a number of custom workspaces as part of the user configuration. Needs further work to allow adding and deleting individual workspaces.
* Bundle a default workspace configuration with Blender (current screen-layouts converted to workspaces).
* Pressing button to add a workspace spawns a menu to select between "Duplicate Current" and the workspaces from the user configuration. If no workspaces are stored in the user configuration, the default workspaces are listed instead.
* Store screen-layouts (`bScreen`) per workspace.
* Store an active screen-layout per workspace. Changing the workspace will enable this layout.
* Store active mode in workspace. Changing the workspace will also enter the mode of the new workspace. (Note that we still store the active mode in the object, moving this completely to workspaces is a separate project.)
* Store an active render layer per workspace.
* Moved mode switch from 3D View header to Info Editor header.
* Store active scene in window (not directly workspace related, but overlaps quite a bit).
* Removed 'Use Global Scene' User Preference option.
* Compatibility with old files - a new workspace is created for every screen-layout of old files. Old Blender versions should be able to read files saved with workspace support as well.
* Default .blend only contains one workspace ("General").
* Support appending workspaces.
Opening files without UI and commandline rendering should work fine.
Note that the UI is temporary! We plan to introduce a new global topbar
that contains the workspace options and tabs for switching workspaces.
== Technical Notes
* Workspaces are data-blocks.
* Adding and removing `bScreen`s should be done through `ED_workspace_layout` API now.
* A workspace can be active in multiple windows at the same time.
* The mode menu (which is now in the Info Editor header) doesn't display "Grease Pencil Edit" mode anymore since its availability depends on the active editor. Will be fixed by making Grease Pencil an own object type (as planned).
* The button to change the active workspace object mode may get out of sync with the mode of the active object. Will either be resolved by moving mode out of object data, or we'll disable workspace modes again (there's a `#define USE_WORKSPACE_MODE` for that).
* Screen-layouts (`bScreen`) are IDs and thus stored in a main list-base. Had to add a wrapper `WorkSpaceLayout` so we can store them in a list-base within workspaces, too. On the long run we could completely replace `bScreen` by workspace structs.
* `WorkSpace` types use some special compiler trickery to allow marking structs and struct members as private. BKE_workspace API should be used for accessing those.
* Added scene operators `SCENE_OT_`. Was previously done through screen operators.
== BPY API Changes
* Removed `Screen.scene`, added `Window.scene`
* Removed `UserPreferencesView.use_global_scene`
* Added `Context.workspace`, `Window.workspace` and `BlendData.workspaces`
* Added `bpy.types.WorkSpace` containing `screens`, `object_mode` and `render_layer`
* Added Screen.layout_name for the layout name that'll be displayed in the UI (may differ from internal name)
== What's left?
* There are a few open design questions (T50521). We should find the needed answers and implement them.
* Allow adding and removing individual workspaces from workspace configuration (needs UI design).
* Get the override system ready and support overrides per workspace.
* Support custom UI setups as part of workspaces (hidden panels, hidden buttons, customizable toolbars, etc).
* Allow enabling add-ons per workspace.
* Support custom workspace keymaps.
* Remove special exception for workspaces in linking code (so they're always appended, never linked). Depends on a few things, so best to solve later.
* Get the topbar done.
* Workspaces need a proper icon, current one is just a placeholder :)
Reviewed By: campbellbarton, mont29
Tags: #user_interface, #bf_blender_2.8
Maniphest Tasks: T50521
Differential Revision: https://developer.blender.org/D2451
2017-06-01 19:56:58 +02:00
|
|
|
for (wmWindow *win = wm->windows.first; win; win = win->next) {
|
|
|
|
bScreen *screen = WM_window_get_active_screen(win);
|
|
|
|
|
|
|
|
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
|
|
|
|
if (sa->spacetype == SPACE_IMAGE) {
|
|
|
|
if (((SpaceImage *)sa->spacedata.first)->mode == SI_MODE_PAINT) {
|
2014-04-01 11:34:00 +11:00
|
|
|
enabled = true;
|
Main Workspace Integration
This commit does the main integration of workspaces, which is a design we agreed on during the 2.8 UI workshop (see https://wiki.blender.org/index.php/Dev:2.8/UI/Workshop_Writeup)
Workspaces should generally be stable, I'm not aware of any remaining bugs (or I've forgotten them :) ). If you find any, let me know!
(Exception: mode switching button might get out of sync with actual mode in some cases, would consider that a limitation/ToDo. Needs to be resolved at some point.)
== Main Changes/Features
* Introduces the new Workspaces as data-blocks.
* Allow storing a number of custom workspaces as part of the user configuration. Needs further work to allow adding and deleting individual workspaces.
* Bundle a default workspace configuration with Blender (current screen-layouts converted to workspaces).
* Pressing button to add a workspace spawns a menu to select between "Duplicate Current" and the workspaces from the user configuration. If no workspaces are stored in the user configuration, the default workspaces are listed instead.
* Store screen-layouts (`bScreen`) per workspace.
* Store an active screen-layout per workspace. Changing the workspace will enable this layout.
* Store active mode in workspace. Changing the workspace will also enter the mode of the new workspace. (Note that we still store the active mode in the object, moving this completely to workspaces is a separate project.)
* Store an active render layer per workspace.
* Moved mode switch from 3D View header to Info Editor header.
* Store active scene in window (not directly workspace related, but overlaps quite a bit).
* Removed 'Use Global Scene' User Preference option.
* Compatibility with old files - a new workspace is created for every screen-layout of old files. Old Blender versions should be able to read files saved with workspace support as well.
* Default .blend only contains one workspace ("General").
* Support appending workspaces.
Opening files without UI and commandline rendering should work fine.
Note that the UI is temporary! We plan to introduce a new global topbar
that contains the workspace options and tabs for switching workspaces.
== Technical Notes
* Workspaces are data-blocks.
* Adding and removing `bScreen`s should be done through `ED_workspace_layout` API now.
* A workspace can be active in multiple windows at the same time.
* The mode menu (which is now in the Info Editor header) doesn't display "Grease Pencil Edit" mode anymore since its availability depends on the active editor. Will be fixed by making Grease Pencil an own object type (as planned).
* The button to change the active workspace object mode may get out of sync with the mode of the active object. Will either be resolved by moving mode out of object data, or we'll disable workspace modes again (there's a `#define USE_WORKSPACE_MODE` for that).
* Screen-layouts (`bScreen`) are IDs and thus stored in a main list-base. Had to add a wrapper `WorkSpaceLayout` so we can store them in a list-base within workspaces, too. On the long run we could completely replace `bScreen` by workspace structs.
* `WorkSpace` types use some special compiler trickery to allow marking structs and struct members as private. BKE_workspace API should be used for accessing those.
* Added scene operators `SCENE_OT_`. Was previously done through screen operators.
== BPY API Changes
* Removed `Screen.scene`, added `Window.scene`
* Removed `UserPreferencesView.use_global_scene`
* Added `Context.workspace`, `Window.workspace` and `BlendData.workspaces`
* Added `bpy.types.WorkSpace` containing `screens`, `object_mode` and `render_layer`
* Added Screen.layout_name for the layout name that'll be displayed in the UI (may differ from internal name)
== What's left?
* There are a few open design questions (T50521). We should find the needed answers and implement them.
* Allow adding and removing individual workspaces from workspace configuration (needs UI design).
* Get the override system ready and support overrides per workspace.
* Support custom UI setups as part of workspaces (hidden panels, hidden buttons, customizable toolbars, etc).
* Allow enabling add-ons per workspace.
* Support custom workspace keymaps.
* Remove special exception for workspaces in linking code (so they're always appended, never linked). Depends on a few things, so best to solve later.
* Get the topbar done.
* Workspaces need a proper icon, current one is just a placeholder :)
Reviewed By: campbellbarton, mont29
Tags: #user_interface, #bf_blender_2.8
Maniphest Tasks: T50521
Differential Revision: https://developer.blender.org/D2451
2017-06-01 19:56:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-08-31 13:04:03 +00:00
|
|
|
|
|
|
|
if (enabled) {
|
2018-11-14 11:20:08 +11:00
|
|
|
BKE_paint_init(bmain, scene, PAINT_MODE_TEXTURE_2D, PAINT_CURSOR_TEXTURE_PAINT);
|
2012-08-31 13:04:03 +00:00
|
|
|
|
2013-03-29 14:02:28 +00:00
|
|
|
paint_cursor_start_explicit(&imapaint->paint, wm, image_paint_poll);
|
2010-10-20 00:42:19 +00:00
|
|
|
}
|
2013-10-09 16:00:15 +00:00
|
|
|
else {
|
|
|
|
paint_cursor_delete_textures();
|
|
|
|
}
|
2010-10-20 00:42:19 +00:00
|
|
|
}
|
|
|
|
|
2009-02-19 23:53:40 +00:00
|
|
|
/************************ grab clone operator ************************/
|
|
|
|
|
|
|
|
typedef struct GrabClone {
|
|
|
|
float startoffset[2];
|
|
|
|
int startx, starty;
|
|
|
|
} GrabClone;
|
|
|
|
|
|
|
|
static void grab_clone_apply(bContext *C, wmOperator *op)
|
|
|
|
{
|
2012-03-28 03:47:33 +00:00
|
|
|
Brush *brush = image_paint_brush(C);
|
2009-02-19 23:53:40 +00:00
|
|
|
float delta[2];
|
|
|
|
|
|
|
|
RNA_float_get_array(op->ptr, "delta", delta);
|
2010-03-05 22:01:42 +00:00
|
|
|
add_v2_v2(brush->clone.offset, delta);
|
2009-02-19 23:53:40 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int grab_clone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
2009-02-19 23:53:40 +00:00
|
|
|
{
|
2012-03-28 03:47:33 +00:00
|
|
|
Brush *brush = image_paint_brush(C);
|
2009-02-19 23:53:40 +00:00
|
|
|
GrabClone *cmv;
|
|
|
|
|
2012-03-28 03:47:33 +00:00
|
|
|
cmv = MEM_callocN(sizeof(GrabClone), "GrabClone");
|
2010-03-05 22:01:42 +00:00
|
|
|
copy_v2_v2(cmv->startoffset, brush->clone.offset);
|
2012-03-28 03:47:33 +00:00
|
|
|
cmv->startx = event->x;
|
|
|
|
cmv->starty = event->y;
|
|
|
|
op->customdata = cmv;
|
2009-02-19 23:53:40 +00:00
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
WM_event_add_modal_handler(C, op);
|
2009-02-19 23:53:40 +00:00
|
|
|
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
|
|
}
|
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int grab_clone_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
2009-02-19 23:53:40 +00:00
|
|
|
{
|
2012-03-28 03:47:33 +00:00
|
|
|
Brush *brush = image_paint_brush(C);
|
|
|
|
ARegion *ar = CTX_wm_region(C);
|
|
|
|
GrabClone *cmv = op->customdata;
|
2009-02-19 23:53:40 +00:00
|
|
|
float startfx, startfy, fx, fy, delta[2];
|
2012-03-28 03:47:33 +00:00
|
|
|
int xmin = ar->winrct.xmin, ymin = ar->winrct.ymin;
|
2009-02-19 23:53:40 +00:00
|
|
|
|
2012-03-28 03:47:33 +00:00
|
|
|
switch (event->type) {
|
2009-02-19 23:53:40 +00:00
|
|
|
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(&ar->v2d, cmv->startx - xmin, cmv->starty - ymin, &startfx, &startfy);
|
|
|
|
UI_view2d_region_to_view(&ar->v2d, event->x - xmin, event->y - ymin, &fx, &fy);
|
|
|
|
|
2012-03-28 03:47:33 +00:00
|
|
|
delta[0] = fx - startfx;
|
|
|
|
delta[1] = fy - startfy;
|
2009-02-19 23:53:40 +00:00
|
|
|
RNA_float_set_array(op->ptr, "delta", delta);
|
|
|
|
|
2010-03-05 22:01:42 +00:00
|
|
|
copy_v2_v2(brush->clone.offset, cmv->startoffset);
|
2009-02-19 23:53:40 +00:00
|
|
|
|
|
|
|
grab_clone_apply(C, op);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
|
|
}
|
|
|
|
|
2013-10-30 23:08:53 +00:00
|
|
|
static void grab_clone_cancel(bContext *UNUSED(C), wmOperator *op)
|
2009-02-19 23:53:40 +00:00
|
|
|
{
|
|
|
|
MEM_freeN(op->customdata);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PAINT_OT_grab_clone(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Grab Clone";
|
|
|
|
ot->idname = "PAINT_OT_grab_clone";
|
2012-05-05 17:10:51 +00:00
|
|
|
ot->description = "Move the clone source image";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-02-19 23:53:40 +00:00
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
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;
|
2009-02-19 23:53:40 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-03-28 03:47:33 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
|
2009-02-19 23:53:40 +00:00
|
|
|
|
|
|
|
/* properties */
|
2011-09-19 12:26:20 +00:00
|
|
|
RNA_def_float_vector(ot->srna, "delta", 2, NULL, -FLT_MAX, FLT_MAX, "Delta", "Delta offset of clone image in 0.0..1.0 coordinates", -1.0f, 1.0f);
|
2009-02-19 23:53:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/******************** sample color operator ********************/
|
2013-10-11 02:23:20 +00:00
|
|
|
typedef struct {
|
|
|
|
bool show_cursor;
|
|
|
|
short event_type;
|
2014-07-21 12:02:05 +02:00
|
|
|
float initcolor[3];
|
|
|
|
bool sample_palette;
|
|
|
|
} SampleColorData;
|
|
|
|
|
|
|
|
|
|
|
|
static void sample_color_update_header(SampleColorData *data, bContext *C)
|
|
|
|
{
|
2016-05-14 10:00:52 +02:00
|
|
|
char msg[UI_MAX_DRAW_STR];
|
2014-07-21 12:02:05 +02:00
|
|
|
ScrArea *sa = CTX_wm_area(C);
|
|
|
|
|
|
|
|
if (sa) {
|
2018-07-02 18:45:26 +02:00
|
|
|
BLI_snprintf(
|
|
|
|
msg, sizeof(msg),
|
|
|
|
IFACE_("Sample color for %s"),
|
|
|
|
!data->sample_palette ?
|
|
|
|
IFACE_("Brush. Use Left Click to sample for palette instead") :
|
|
|
|
IFACE_("Palette. Use Left Click to sample more colors"));
|
2018-06-26 17:19:25 +02:00
|
|
|
ED_workspace_status_text(C, msg);
|
2014-07-21 12:02:05 +02:00
|
|
|
}
|
|
|
|
}
|
2013-10-11 02:23:20 +00:00
|
|
|
|
2009-02-19 23:53:40 +00:00
|
|
|
static int sample_color_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
2013-10-11 02:23:20 +00:00
|
|
|
Paint *paint = BKE_paint_get_active_from_context(C);
|
|
|
|
Brush *brush = BKE_paint_brush(paint);
|
2017-10-17 13:43:10 +11:00
|
|
|
ePaintMode mode = BKE_paintmode_get_active_from_context(C);
|
2012-03-28 03:47:33 +00:00
|
|
|
ARegion *ar = CTX_wm_region(C);
|
2013-10-15 13:45:27 +00:00
|
|
|
wmWindow *win = CTX_wm_window(C);
|
2016-02-04 15:26:07 +11:00
|
|
|
const bool show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0);
|
2009-02-19 23:53:40 +00:00
|
|
|
int location[2];
|
2013-10-15 13:45:27 +00:00
|
|
|
paint->flags &= ~PAINT_SHOW_BRUSH;
|
|
|
|
|
|
|
|
/* force redraw without cursor */
|
|
|
|
WM_paint_cursor_tag_redraw(win, ar);
|
|
|
|
WM_redraw_windows(C);
|
|
|
|
|
2009-02-19 23:53:40 +00:00
|
|
|
RNA_int_get_array(op->ptr, "location", location);
|
2016-02-04 15:26:07 +11:00
|
|
|
const bool use_palette = RNA_boolean_get(op->ptr, "palette");
|
2018-11-14 11:20:08 +11:00
|
|
|
const bool use_sample_texture = (mode == PAINT_MODE_TEXTURE_3D) && !RNA_boolean_get(op->ptr, "merged");
|
2014-07-21 12:02:05 +02:00
|
|
|
|
2016-02-04 15:26:07 +11:00
|
|
|
paint_sample_color(C, ar, location[0], location[1], use_sample_texture, use_palette);
|
2009-02-19 23:53:40 +00:00
|
|
|
|
2013-10-16 04:08:20 +00:00
|
|
|
if (show_cursor) {
|
2013-10-15 13:45:27 +00:00
|
|
|
paint->flags |= PAINT_SHOW_BRUSH;
|
|
|
|
}
|
|
|
|
|
2012-03-28 03:47:33 +00:00
|
|
|
WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-02-19 23:53:40 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
2009-02-19 23:53:40 +00:00
|
|
|
{
|
2014-07-21 12:02:05 +02:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
2013-10-11 02:23:20 +00:00
|
|
|
Paint *paint = BKE_paint_get_active_from_context(C);
|
2014-02-28 18:12:05 +01:00
|
|
|
Brush *brush = BKE_paint_brush(paint);
|
2013-10-11 02:23:20 +00:00
|
|
|
SampleColorData *data = MEM_mallocN(sizeof(SampleColorData), "sample color custom data");
|
2013-10-15 13:45:27 +00:00
|
|
|
ARegion *ar = CTX_wm_region(C);
|
|
|
|
wmWindow *win = CTX_wm_window(C);
|
2013-10-11 02:23:20 +00:00
|
|
|
|
|
|
|
data->event_type = event->type;
|
|
|
|
data->show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0);
|
2014-07-21 12:02:05 +02:00
|
|
|
copy_v3_v3(data->initcolor, BKE_brush_color_get(scene, brush));
|
|
|
|
data->sample_palette = false;
|
2013-10-11 02:23:20 +00:00
|
|
|
op->customdata = data;
|
|
|
|
paint->flags &= ~PAINT_SHOW_BRUSH;
|
|
|
|
|
2014-07-21 12:02:05 +02:00
|
|
|
sample_color_update_header(data, C);
|
|
|
|
|
|
|
|
WM_event_add_modal_handler(C, op);
|
|
|
|
|
2013-10-15 13:45:27 +00:00
|
|
|
/* force redraw without cursor */
|
|
|
|
WM_paint_cursor_tag_redraw(win, ar);
|
|
|
|
WM_redraw_windows(C);
|
|
|
|
|
2011-05-20 07:40:05 +00:00
|
|
|
RNA_int_set_array(op->ptr, "location", event->mval);
|
2014-07-21 12:02:05 +02:00
|
|
|
|
2017-10-17 13:43:10 +11:00
|
|
|
ePaintMode mode = BKE_paintmode_get_active_from_context(C);
|
2018-11-14 11:20:08 +11:00
|
|
|
const bool use_sample_texture = (mode == PAINT_MODE_TEXTURE_3D) && !RNA_boolean_get(op->ptr, "merged");
|
2016-03-30 17:28:01 +11:00
|
|
|
|
|
|
|
paint_sample_color(C, ar, event->mval[0], event->mval[1], use_sample_texture, false);
|
2014-04-30 07:48:54 +10:00
|
|
|
WM_cursor_modal_set(win, BC_EYEDROPPER_CURSOR);
|
2010-09-16 21:03:07 +00:00
|
|
|
|
2014-02-28 18:12:05 +01:00
|
|
|
WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
|
2009-02-19 23:53:40 +00:00
|
|
|
|
2010-09-16 21:03:07 +00:00
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
|
|
}
|
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
2010-09-16 21:03:07 +00:00
|
|
|
{
|
2014-07-21 12:02:05 +02:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
2013-10-11 02:23:20 +00:00
|
|
|
SampleColorData *data = op->customdata;
|
2013-10-15 13:45:27 +00:00
|
|
|
Paint *paint = BKE_paint_get_active_from_context(C);
|
|
|
|
Brush *brush = BKE_paint_brush(paint);
|
2013-10-11 02:23:20 +00:00
|
|
|
|
|
|
|
if ((event->type == data->event_type) && (event->val == KM_RELEASE)) {
|
2013-10-16 04:08:20 +00:00
|
|
|
if (data->show_cursor) {
|
2013-10-11 02:23:20 +00:00
|
|
|
paint->flags |= PAINT_SHOW_BRUSH;
|
|
|
|
}
|
|
|
|
|
2014-07-21 12:02:05 +02:00
|
|
|
if (data->sample_palette) {
|
|
|
|
BKE_brush_color_set(scene, brush, data->initcolor);
|
|
|
|
RNA_boolean_set(op->ptr, "palette", true);
|
|
|
|
}
|
2014-03-23 00:33:55 +02:00
|
|
|
WM_cursor_modal_restore(CTX_wm_window(C));
|
2013-10-11 02:23:20 +00:00
|
|
|
MEM_freeN(data);
|
2018-06-26 17:19:25 +02:00
|
|
|
ED_workspace_status_text(C, NULL);
|
2014-07-21 12:02:05 +02:00
|
|
|
|
2013-04-11 14:15:25 +00:00
|
|
|
return OPERATOR_FINISHED;
|
2013-10-11 02:23:20 +00:00
|
|
|
}
|
2013-04-11 14:15:25 +00:00
|
|
|
|
2017-10-17 13:43:10 +11:00
|
|
|
ePaintMode mode = BKE_paintmode_get_active_from_context(C);
|
2018-11-14 11:20:08 +11:00
|
|
|
const bool use_sample_texture = (mode == PAINT_MODE_TEXTURE_3D) && !RNA_boolean_get(op->ptr, "merged");
|
2016-02-04 15:26:07 +11:00
|
|
|
|
2012-03-28 03:47:33 +00:00
|
|
|
switch (event->type) {
|
2010-09-16 21:03:07 +00:00
|
|
|
case MOUSEMOVE:
|
2013-10-15 13:45:27 +00:00
|
|
|
{
|
|
|
|
ARegion *ar = CTX_wm_region(C);
|
2011-05-20 07:40:05 +00:00
|
|
|
RNA_int_set_array(op->ptr, "location", event->mval);
|
2016-02-04 15:26:07 +11:00
|
|
|
paint_sample_color(C, ar, event->mval[0], event->mval[1], use_sample_texture, false);
|
2013-10-15 13:45:27 +00:00
|
|
|
WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
|
2010-09-16 21:03:07 +00:00
|
|
|
break;
|
2013-10-15 13:45:27 +00:00
|
|
|
}
|
2014-07-21 12:02:05 +02:00
|
|
|
|
|
|
|
case LEFTMOUSE:
|
|
|
|
if (event->val == KM_PRESS) {
|
|
|
|
ARegion *ar = CTX_wm_region(C);
|
|
|
|
RNA_int_set_array(op->ptr, "location", event->mval);
|
2016-02-04 15:26:07 +11:00
|
|
|
paint_sample_color(C, ar, event->mval[0], event->mval[1], use_sample_texture, true);
|
2014-07-21 12:02:05 +02:00
|
|
|
if (!data->sample_palette) {
|
|
|
|
data->sample_palette = true;
|
|
|
|
sample_color_update_header(data, C);
|
|
|
|
}
|
2014-10-17 14:25:50 +02:00
|
|
|
WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
|
2014-07-21 12:02:05 +02:00
|
|
|
}
|
|
|
|
break;
|
2010-09-16 21:03:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
2009-02-19 23:53:40 +00:00
|
|
|
}
|
|
|
|
|
2019-01-04 08:02:17 +11:00
|
|
|
static bool sample_color_poll(bContext *C)
|
|
|
|
{
|
|
|
|
return (image_paint_poll_ignore_tool(C) || vertex_paint_poll_ignore_tool(C));
|
|
|
|
}
|
|
|
|
|
2009-02-19 23:53:40 +00:00
|
|
|
void PAINT_OT_sample_color(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Sample Color";
|
|
|
|
ot->idname = "PAINT_OT_sample_color";
|
2012-05-05 17:10:51 +00:00
|
|
|
ot->description = "Use the mouse to sample a color in the image";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-02-19 23:53:40 +00:00
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = sample_color_exec;
|
|
|
|
ot->invoke = sample_color_invoke;
|
|
|
|
ot->modal = sample_color_modal;
|
2019-01-04 08:02:17 +11:00
|
|
|
ot->poll = sample_color_poll;
|
2009-02-19 23:53:40 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-03-28 03:47:33 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2009-02-19 23:53:40 +00:00
|
|
|
|
|
|
|
/* properties */
|
2016-02-04 15:26:07 +11:00
|
|
|
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", "");
|
2009-02-19 23:53:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/******************** texture paint toggle operator ********************/
|
|
|
|
|
2018-07-02 11:47:00 +02:00
|
|
|
static bool texture_paint_toggle_poll(bContext *C)
|
2009-02-19 23:53:40 +00:00
|
|
|
{
|
2013-08-29 10:34:09 +00:00
|
|
|
Object *ob = CTX_data_active_object(C);
|
|
|
|
if (ob == NULL || ob->type != OB_MESH)
|
2009-02-19 23:53:40 +00:00
|
|
|
return 0;
|
2017-11-06 17:17:10 +01:00
|
|
|
if (!ob->data || ID_IS_LINKED(ob->data))
|
2013-08-29 10:34:09 +00:00
|
|
|
return 0;
|
|
|
|
if (CTX_data_edit_object(C))
|
2009-02-19 23:53:40 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int texture_paint_toggle_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
2018-05-08 07:22:52 +02:00
|
|
|
struct wmMsgBus *mbus = CTX_wm_message_bus(C);
|
2018-06-25 12:32:48 +02:00
|
|
|
Main *bmain = CTX_data_main(C);
|
2012-03-28 03:47:33 +00:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
Object *ob = CTX_data_active_object(C);
|
2013-08-29 10:34:09 +00:00
|
|
|
const int mode_flag = OB_MODE_TEXTURE_PAINT;
|
2018-04-05 18:20:27 +02:00
|
|
|
const bool is_mode_set = (ob->mode & mode_flag) != 0;
|
2013-08-29 10:34:09 +00:00
|
|
|
|
|
|
|
if (!is_mode_set) {
|
2018-04-05 18:20:27 +02:00
|
|
|
if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
|
2013-08-29 10:34:09 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
2009-02-19 23:53:40 +00:00
|
|
|
}
|
|
|
|
|
2018-04-05 18:20:27 +02:00
|
|
|
if (ob->mode & mode_flag) {
|
|
|
|
ob->mode &= ~mode_flag;
|
2009-03-17 21:44:58 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (U.glreslimit != 0)
|
2018-06-25 12:32:48 +02:00
|
|
|
GPU_free_images(bmain);
|
|
|
|
GPU_paint_set_mipmap(bmain, 1);
|
2009-03-17 21:44:58 +00:00
|
|
|
|
2009-02-19 23:53:40 +00:00
|
|
|
toggle_paint_cursor(C, 0);
|
|
|
|
}
|
|
|
|
else {
|
2014-07-21 12:02:05 +02:00
|
|
|
bScreen *sc;
|
2014-08-28 16:40:38 +02:00
|
|
|
Image *ima = NULL;
|
|
|
|
ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
|
2014-07-21 12:02:05 +02:00
|
|
|
|
|
|
|
/* This has to stay here to regenerate the texture paint
|
|
|
|
* cache in case we are loading a file */
|
2019-03-07 19:39:50 +01:00
|
|
|
BKE_texpaint_slots_refresh_object(scene, ob);
|
2014-07-21 12:02:05 +02:00
|
|
|
|
2014-10-06 15:12:06 +02:00
|
|
|
BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2014-08-28 16:40:38 +02:00
|
|
|
/* entering paint mode also sets image to editors */
|
|
|
|
if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) {
|
2019-01-15 23:24:20 +11:00
|
|
|
/* set the current material active paint slot on image editor */
|
|
|
|
Material *ma = give_current_material(ob, ob->actcol);
|
2014-07-21 12:02:05 +02:00
|
|
|
|
2014-10-06 15:12:06 +02:00
|
|
|
if (ma && ma->texpaintslot)
|
2014-08-28 16:40:38 +02:00
|
|
|
ima = ma->texpaintslot[ma->paint_active_slot].ima;
|
|
|
|
}
|
2015-04-04 22:38:31 +02:00
|
|
|
else if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
|
2014-08-28 16:40:38 +02:00
|
|
|
ima = imapaint->canvas;
|
2018-06-04 09:31:30 +02:00
|
|
|
}
|
|
|
|
|
2014-10-06 15:12:06 +02:00
|
|
|
if (ima) {
|
2019-03-08 09:29:17 +11:00
|
|
|
for (sc = bmain->screens.first; sc; sc = sc->id.next) {
|
2014-10-06 15:12:06 +02:00
|
|
|
ScrArea *sa;
|
|
|
|
for (sa = sc->areabase.first; sa; sa = sa->next) {
|
|
|
|
SpaceLink *sl;
|
|
|
|
for (sl = sa->spacedata.first; sl; sl = sl->next) {
|
|
|
|
if (sl->spacetype == SPACE_IMAGE) {
|
|
|
|
SpaceImage *sima = (SpaceImage *)sl;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2018-02-13 19:29:08 +11:00
|
|
|
if (!sima->pin) {
|
|
|
|
Object *obedit = CTX_data_edit_object(C);
|
2019-03-11 12:44:14 +01:00
|
|
|
ED_space_image_set(bmain, sima, obedit, ima, true);
|
2018-02-13 19:29:08 +11:00
|
|
|
}
|
2014-10-06 15:12:06 +02:00
|
|
|
}
|
2014-07-21 12:02:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2018-04-05 18:20:27 +02:00
|
|
|
ob->mode |= mode_flag;
|
2009-02-19 23:53:40 +00:00
|
|
|
|
2018-11-14 11:20:08 +11:00
|
|
|
BKE_paint_init(bmain, scene, PAINT_MODE_TEXTURE_3D, PAINT_CURSOR_TEXTURE_PAINT);
|
2009-03-17 21:44:58 +00:00
|
|
|
|
2018-11-05 16:18:43 +11:00
|
|
|
BKE_paint_toolslots_brush_validate(bmain, &imapaint->paint);
|
2018-11-03 16:52:06 +11:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (U.glreslimit != 0)
|
2018-06-25 12:32:48 +02:00
|
|
|
GPU_free_images(bmain);
|
|
|
|
GPU_paint_set_mipmap(bmain, 0);
|
2009-03-17 21:44:58 +00:00
|
|
|
|
2009-02-19 23:53:40 +00:00
|
|
|
toggle_paint_cursor(C, 1);
|
|
|
|
}
|
|
|
|
|
2018-06-26 12:31:06 +02:00
|
|
|
Mesh *me = BKE_mesh_from_object(ob);
|
|
|
|
BLI_assert(me != NULL);
|
2018-12-06 17:52:37 +01:00
|
|
|
DEG_id_tag_update(&me->id, ID_RECALC_COPY_ON_WRITE);
|
2018-06-26 12:31:06 +02:00
|
|
|
|
2012-03-28 03:47:33 +00:00
|
|
|
WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
|
2009-02-19 23:53:40 +00:00
|
|
|
|
2018-05-08 07:22:52 +02:00
|
|
|
WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
|
|
|
|
|
2018-05-16 18:41:11 +02:00
|
|
|
WM_toolsystem_update_from_context_view3d(C);
|
|
|
|
|
2009-02-19 23:53:40 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PAINT_OT_texture_paint_toggle(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Texture Paint Toggle";
|
|
|
|
ot->idname = "PAINT_OT_texture_paint_toggle";
|
2012-05-05 17:10:51 +00:00
|
|
|
ot->description = "Toggle texture paint mode in 3D view";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-02-19 23:53:40 +00:00
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = texture_paint_toggle_exec;
|
|
|
|
ot->poll = texture_paint_toggle_poll;
|
2009-02-19 23:53:40 +00:00
|
|
|
|
|
|
|
/* flags */
|
2018-11-30 11:57:14 +01:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
|
2009-02-19 23:53:40 +00:00
|
|
|
}
|
|
|
|
|
2014-07-21 12:02:05 +02:00
|
|
|
|
|
|
|
static int brush_colors_flip_exec(bContext *C, wmOperator *UNUSED(op))
|
|
|
|
{
|
2019-01-08 23:24:38 +11:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
|
2017-09-28 01:38:17 +10:00
|
|
|
|
2019-01-08 23:24:38 +11:00
|
|
|
ViewLayer *view_layer = CTX_data_view_layer(C);
|
|
|
|
Paint *paint = BKE_paint_get_active(scene, view_layer);
|
|
|
|
Brush *br = BKE_paint_brush(paint);
|
2017-09-28 01:38:17 +10:00
|
|
|
|
2014-07-21 12:02:05 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, br);
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2018-07-02 11:47:00 +02:00
|
|
|
static bool brush_colors_flip_poll(bContext *C)
|
2014-07-21 12:02:05 +02:00
|
|
|
{
|
|
|
|
if (image_paint_poll(C)) {
|
|
|
|
Brush *br = image_paint_brush(C);
|
2019-03-08 15:53:38 +01:00
|
|
|
if (ELEM(br->imagepaint_tool, PAINT_TOOL_DRAW, PAINT_TOOL_FILL))
|
2019-01-08 23:24:38 +11:00
|
|
|
return true;
|
2014-07-21 12:02:05 +02:00
|
|
|
}
|
2017-09-28 01:38:17 +10:00
|
|
|
else {
|
|
|
|
Object *ob = CTX_data_active_object(C);
|
2019-01-08 23:24:38 +11:00
|
|
|
if (ob != NULL) {
|
|
|
|
if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_TEXTURE_PAINT)) {
|
|
|
|
return true;
|
|
|
|
}
|
2017-09-28 01:38:17 +10:00
|
|
|
}
|
|
|
|
}
|
2019-01-08 23:24:38 +11:00
|
|
|
return false;
|
2014-07-21 12:02:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void PAINT_OT_brush_colors_flip(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Brush Colors Flip";
|
|
|
|
ot->idname = "PAINT_OT_brush_colors_flip";
|
|
|
|
ot->description = "Toggle foreground and background 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)
|
|
|
|
{
|
2018-03-19 14:17:59 +01:00
|
|
|
wmWindowManager *wm = CTX_wm_manager(C);
|
2014-09-20 23:47:10 +02:00
|
|
|
SpaceImage *sima = CTX_wm_space_image(C);
|
|
|
|
Image *ima = sima->image;
|
|
|
|
|
2018-03-19 14:17:59 +01:00
|
|
|
BKE_undosys_step_push_init_with_type(wm->undo_stack, C, op->type->name, BKE_UNDOSYS_TYPE_IMAGE);
|
|
|
|
|
2019-02-05 14:24:11 +11:00
|
|
|
ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D);
|
2014-07-21 12:02:05 +02:00
|
|
|
|
|
|
|
paint_2d_bucket_fill(C, color, NULL, NULL, NULL);
|
|
|
|
|
2018-03-19 14:17:59 +01:00
|
|
|
BKE_undosys_step_push(wm->undo_stack, C, op->type->name);
|
2014-09-20 23:47:10 +02:00
|
|
|
|
2017-06-08 10:14:53 +02:00
|
|
|
DEG_id_tag_update(&ima->id, 0);
|
2014-07-21 12:02:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-07-02 11:47:00 +02:00
|
|
|
static bool texture_paint_poll(bContext *C)
|
2009-02-23 16:31:58 +00:00
|
|
|
{
|
2018-04-05 18:20:27 +02:00
|
|
|
if (texture_paint_toggle_poll(C))
|
|
|
|
if (CTX_data_active_object(C)->mode & OB_MODE_TEXTURE_PAINT)
|
2009-02-23 16:31:58 +00:00
|
|
|
return 1;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-02-23 16:31:58 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-07-02 11:47:00 +02:00
|
|
|
bool image_texture_paint_poll(bContext *C)
|
2009-10-22 23:22:05 +00:00
|
|
|
{
|
|
|
|
return (texture_paint_poll(C) || image_paint_poll(C));
|
|
|
|
}
|
|
|
|
|
2018-07-02 11:47:00 +02:00
|
|
|
bool facemask_paint_poll(bContext *C)
|
2009-11-01 00:06:53 +00:00
|
|
|
{
|
2018-04-05 18:20:27 +02:00
|
|
|
return BKE_paint_select_face_test(CTX_data_active_object(C));
|
2009-11-01 00:06:53 +00:00
|
|
|
}
|
2009-11-04 20:19:41 +00:00
|
|
|
|
2018-07-02 11:47:00 +02:00
|
|
|
bool vert_paint_poll(bContext *C)
|
2011-07-12 19:06:06 +00:00
|
|
|
{
|
2018-04-05 18:20:27 +02:00
|
|
|
return BKE_paint_select_vert_test(CTX_data_active_object(C));
|
2011-07-12 19:06:06 +00:00
|
|
|
}
|
2011-09-18 17:10:28 +00:00
|
|
|
|
2018-07-02 11:47:00 +02:00
|
|
|
bool mask_paint_poll(bContext *C)
|
2011-07-18 17:38:17 +00:00
|
|
|
{
|
2018-04-05 18:20:27 +02:00
|
|
|
return BKE_paint_select_elem_test(CTX_data_active_object(C));
|
2011-07-18 17:38:17 +00:00
|
|
|
}
|