Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/sculpt_paint/paint_image.c')
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c119
1 files changed, 88 insertions, 31 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index d0f8e36e17d..c60097e20eb 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -316,7 +316,7 @@ typedef struct ProjPaintState {
float normal_angle_range; /* difference between normal_angle and normal_angle_inner, for easy access */
short is_ortho;
- short is_airbrush; /* only to avoid using (ps.brush->flag & BRUSH_AIRBRUSH) */
+ bool do_masking; /* use masking during painting. Some operations such as airbrush may disable */
short is_texbrush; /* only to avoid running */
#ifndef PROJ_DEBUG_NOSEAMBLEED
float seam_bleed_px;
@@ -355,7 +355,7 @@ typedef union pixelStore {
typedef struct ProjPixel {
float projCoSS[2]; /* the floating point screen projection of this pixel */
-
+ float worldCoSS[3];
/* Only used when the airbrush is disabled.
* Store the max mask value to avoid painting over an area with a lower opacity
* with an advantage that we can avoid touching the pixel at all, if the
@@ -1526,6 +1526,7 @@ static int project_paint_pixel_sizeof(const short tool)
}
}
+
/* run this function when we know a bucket's, face's pixel can be initialized,
* return the ProjPixel which is added to 'ps->bucketRect[bucket_index]' */
static ProjPixel *project_paint_uvpixel_init(
@@ -1537,6 +1538,7 @@ static ProjPixel *project_paint_uvpixel_init(
const int face_index,
const int image_index,
const float pixelScreenCo[4],
+ const float world_spaceCo[3],
const int side,
const float w[3])
{
@@ -1565,6 +1567,10 @@ static ProjPixel *project_paint_uvpixel_init(
}
/* screenspace unclamped, we could keep its z and w values but don't need them at the moment */
+ if (ps->brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) {
+ copy_v3_v3(projPixel->worldCoSS, world_spaceCo);
+ }
+
copy_v2_v2(projPixel->projCoSS, pixelScreenCo);
projPixel->x_px = x_px;
@@ -2374,6 +2380,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
float *uv1co, *uv2co, *uv3co; /* for convenience only, these will be assigned to tf->uv[0],1,2 or tf->uv[0],2,3 */
float pixelScreenCo[4];
+ bool do_3d_mapping = ps->brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D;
rcti bounds_px; /* ispace bounds */
/* vars for getting uvspace bounds */
@@ -2449,7 +2456,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
v1coSS = ps->screenCoords[(*(&mf->v1 + i1))];
v2coSS = ps->screenCoords[(*(&mf->v1 + i2))];
v3coSS = ps->screenCoords[(*(&mf->v1 + i3))];
-
+
/* This funtion gives is a concave polyline in UV space from the clipped quad and tri*/
project_bucket_clip_face(
is_ortho, bucket_bounds,
@@ -2501,9 +2508,9 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
else screen_px_from_persp(uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
/* a pity we need to get the worldspace pixel location here */
- if (do_clip) {
+ if (do_clip || do_3d_mapping) {
interp_v3_v3v3v3(wco, ps->dm_mvert[(*(&mf->v1 + i1))].co, ps->dm_mvert[(*(&mf->v1 + i2))].co, ps->dm_mvert[(*(&mf->v1 + i3))].co, w);
- if (ED_view3d_clipping_test(ps->rv3d, wco, TRUE)) {
+ if (do_clip && ED_view3d_clipping_test(ps->rv3d, wco, TRUE)) {
continue; /* Watch out that no code below this needs to run */
}
}
@@ -2514,13 +2521,13 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
if ((ps->do_occlude == FALSE) ||
!project_bucket_point_occluded(ps, bucketFaceNodes, face_index, pixelScreenCo))
{
-
mask = project_paint_uvpixel_mask(ps, face_index, side, w);
-
+
if (mask > 0.0f) {
BLI_linklist_prepend_arena(
bucketPixelNodes,
- project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index, image_index, pixelScreenCo, side, w),
+ project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index,
+ image_index, pixelScreenCo, wco, side, w),
arena
);
}
@@ -2725,11 +2732,11 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
}
/* a pity we need to get the worldspace pixel location here */
- if (do_clip) {
+ if (do_clip || do_3d_mapping) {
if (side) interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w);
else interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w);
- if (ED_view3d_clipping_test(ps->rv3d, wco, TRUE)) {
+ if (do_clip && ED_view3d_clipping_test(ps->rv3d, wco, TRUE)) {
continue; /* Watch out that no code below this needs to run */
}
}
@@ -2739,7 +2746,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
if (mask > 0.0f) {
BLI_linklist_prepend_arena(
bucketPixelNodes,
- project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index, image_index, pixelScreenCo, side, w),
+ project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index, image_index, pixelScreenCo, wco, side, w),
arena
);
}
@@ -3749,6 +3756,8 @@ typedef struct ProjectHandle {
/* thread settings */
int thread_index;
+
+ struct ImagePool *pool;
} ProjectHandle;
static void blend_color_mix(unsigned char cp[4], const unsigned char cp1[4], const unsigned char cp2[4], const int fac)
@@ -3800,7 +3809,7 @@ static void blend_color_mix_accum_float(float cp[4], const float cp1[4], const u
static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask)
{
- if (ps->is_airbrush == 0 && mask < 1.0f) {
+ if (ps->do_masking && mask < 1.0f) {
projPixel->newColor.uint = IMB_blend_color(projPixel->newColor.uint, ((ProjPixelClone *)projPixel)->clonepx.uint, (int)(alpha * 255), ps->blend);
blend_color_mix(projPixel->pixel.ch_pt, projPixel->origColor.ch, projPixel->newColor.ch, (int)(mask * 255));
}
@@ -3811,7 +3820,7 @@ static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, floa
static void do_projectpaint_clone_f(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask)
{
- if (ps->is_airbrush == 0 && mask < 1.0f) {
+ if (ps->do_masking && mask < 1.0f) {
IMB_blend_color_float(projPixel->newColor.f, projPixel->newColor.f, ((ProjPixelClone *)projPixel)->clonepx.f, alpha, ps->blend);
blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f, projPixel->newColor.f, mask);
}
@@ -3946,7 +3955,7 @@ static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, const
rgba_ub[3] = 255;
}
- if (ps->is_airbrush == 0 && mask < 1.0f) {
+ if (ps->do_masking && mask < 1.0f) {
projPixel->newColor.uint = IMB_blend_color(projPixel->newColor.uint, *((unsigned int *)rgba_ub), (int)(alpha * 255), ps->blend);
blend_color_mix(projPixel->pixel.ch_pt, projPixel->origColor.ch, projPixel->newColor.ch, (int)(mask * 255));
}
@@ -3978,7 +3987,7 @@ static void do_projectpaint_draw_f(ProjPaintState *ps, ProjPixel *projPixel, flo
rgba[3] = 1.0;
}
- if (ps->is_airbrush == 0 && mask < 1.0f) {
+ if (ps->do_masking && mask < 1.0f) {
IMB_blend_color_float(projPixel->newColor.f, projPixel->newColor.f, rgba, alpha, ps->blend);
blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f, projPixel->newColor.f, mask);
}
@@ -3998,10 +4007,12 @@ static void *do_projectpaint_thread(void *ph_v)
const float *lastpos = ((ProjectHandle *)ph_v)->prevmval;
const float *pos = ((ProjectHandle *)ph_v)->mval;
const int thread_index = ((ProjectHandle *)ph_v)->thread_index;
+ struct ImagePool *pool = ((ProjectHandle *)ph_v)->pool;
/* Done with args from ProjectHandle */
LinkNode *node;
ProjPixel *projPixel;
+ Brush *brush = ps->brush;
int last_index = -1;
ProjPaintImage *last_projIma = NULL;
@@ -4021,10 +4032,10 @@ static void *do_projectpaint_thread(void *ph_v)
float co[2];
float mask = 1.0f; /* airbrush wont use mask */
unsigned short mask_short;
- const float radius = (float)BKE_brush_size_get(ps->scene, ps->brush);
+ const float radius = (float)BKE_brush_size_get(ps->scene, brush);
const float radius_squared = radius * radius; /* avoid a square root with every dist comparison */
- short lock_alpha = ELEM(ps->brush->blend, IMB_BLEND_ERASE_ALPHA, IMB_BLEND_ADD_ALPHA) ? 0 : ps->brush->flag & BRUSH_LOCK_ALPHA;
+ short lock_alpha = ELEM(brush->blend, IMB_BLEND_ERASE_ALPHA, IMB_BLEND_ADD_ALPHA) ? 0 : brush->flag & BRUSH_LOCK_ALPHA;
LinkNode *smearPixels = NULL;
LinkNode *smearPixels_f = NULL;
@@ -4105,23 +4116,36 @@ static void *do_projectpaint_thread(void *ph_v)
/*if (dist < radius) {*/ /* correct but uses a sqrtf */
if (dist_nosqrt <= radius_squared) {
+ float samplecos[3];
dist = sqrtf(dist_nosqrt);
falloff = BKE_brush_curve_strength_clamp(ps->brush, dist, radius);
+ if (ps->is_texbrush) {
+ MTex *mtex = &brush->mtex;
+ if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
+ sub_v2_v2v2(samplecos, projPixel->projCoSS, pos);
+ }
+ /* taking 3d copy to account for 3D mapping too. It gets concatenated during sampling */
+ else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D)
+ copy_v3_v3(samplecos, projPixel->worldCoSS);
+ else
+ copy_v3_v3(samplecos, projPixel->projCoSS);
+ }
+
if (falloff > 0.0f) {
if (ps->is_texbrush) {
/* note, for clone and smear, we only use the alpha, could be a special function */
- BKE_brush_sample_tex(ps->scene, ps->brush, projPixel->projCoSS, rgba, thread_index);
+ BKE_brush_sample_tex(ps->scene, brush, samplecos, rgba, thread_index, pool);
alpha = rgba[3];
}
else {
alpha = 1.0f;
}
- if (ps->is_airbrush) {
+ if (!ps->do_masking) {
/* for an aurbrush there is no real mask, so just multiply the alpha by it */
- alpha *= falloff * BKE_brush_alpha_get(ps->scene, ps->brush);
+ alpha *= falloff * BKE_brush_alpha_get(ps->scene, brush);
mask = ((float)projPixel->mask) / 65535.0f;
}
else {
@@ -4129,7 +4153,7 @@ static void *do_projectpaint_thread(void *ph_v)
falloff = 1.0f - falloff;
falloff = 1.0f - (falloff * falloff);
- mask_short = (unsigned short)(projPixel->mask * (BKE_brush_alpha_get(ps->scene, ps->brush) * falloff));
+ mask_short = (unsigned short)(projPixel->mask * (BKE_brush_alpha_get(ps->scene, brush) * falloff));
if (mask_short > projPixel->mask_max) {
mask = ((float)mask_short) / 65535.0f;
projPixel->mask_max = mask_short;
@@ -4248,6 +4272,8 @@ static int project_paint_op(void *state, ImBuf *UNUSED(ibufb), const float lastp
ListBase threads;
int a, i;
+ struct ImagePool *pool;
+
if (!project_bucket_iter_init(ps, pos)) {
return 0;
}
@@ -4255,6 +4281,8 @@ static int project_paint_op(void *state, ImBuf *UNUSED(ibufb), const float lastp
if (ps->thread_tot > 1)
BLI_init_threads(&threads, do_projectpaint_thread, ps->thread_tot);
+ pool = BKE_image_pool_new();
+
/* get the threads running */
for (a = 0; a < ps->thread_tot; a++) {
@@ -4278,6 +4306,8 @@ static int project_paint_op(void *state, ImBuf *UNUSED(ibufb), const float lastp
memcpy(handles[a].projImages[i].partRedrawRect, ps->projImages[i].partRedrawRect, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
}
+ handles[a].pool = pool;
+
if (ps->thread_tot > 1)
BLI_insert_thread(&threads, &handles[a]);
}
@@ -4288,6 +4318,8 @@ static int project_paint_op(void *state, ImBuf *UNUSED(ibufb), const float lastp
do_projectpaint_thread(&handles[0]);
+ BKE_image_pool_free(pool);
+
/* move threaded bounds back into ps->projectPartialRedraws */
for (i = 0; i < ps->image_tot; i++) {
int touch = 0;
@@ -4714,6 +4746,7 @@ static int imapaint_canvas_set(ImagePaintState *s, Image *ima)
if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) {
BKE_image_release_ibuf(ima, ibuf, NULL);
+ BKE_image_release_ibuf(s->image, s->canvas, NULL);
return 0;
}
@@ -4955,7 +4988,6 @@ typedef struct PaintOperation {
int first;
int prevmouse[2];
- float prev_pressure; /* need this since we don't get tablet events for pressure change */
int orig_brush_size;
double starttime;
@@ -4998,7 +5030,9 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps)
ps->pixel_sizeof = project_paint_pixel_sizeof(ps->tool);
BLI_assert(ps->pixel_sizeof >= sizeof(ProjPixel));
- ps->is_airbrush = (brush->flag & BRUSH_AIRBRUSH) ? 1 : 0;
+ /* disable for 3d mapping also because painting on mirrored mesh can create "stripes" */
+ ps->do_masking = (brush->flag & BRUSH_AIRBRUSH || brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW ||
+ brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) ? false : true;
ps->is_texbrush = (brush->mtex.tex) ? 1 : 0;
@@ -5173,6 +5207,11 @@ static int texture_paint_init(bContext *C, wmOperator *op)
/* create painter */
pop->painter = BKE_brush_painter_new(scene, pop->s.brush);
+ {
+ UnifiedPaintSettings *ups = &settings->unified_paint_settings;
+ ups->draw_pressure = true;
+ }
+
return 1;
}
@@ -5261,6 +5300,11 @@ static void paint_exit(bContext *C, wmOperator *op)
BKE_reportf(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted: %s", pop->s.warnpackedfile);
MEM_freeN(pop);
+
+ {
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ ups->draw_pressure = false;
+ }
}
static int paint_exec(bContext *C, wmOperator *op)
@@ -5285,7 +5329,6 @@ static void paint_apply_event(bContext *C, wmOperator *op, wmEvent *event)
{
const Scene *scene = CTX_data_scene(C);
PaintOperation *pop = op->customdata;
- wmTabletData *wmtab;
PointerRNA itemptr;
float pressure, mousef[2];
double time;
@@ -5296,16 +5339,17 @@ static void paint_apply_event(bContext *C, wmOperator *op, wmEvent *event)
tablet = 0;
pop->s.blend = pop->s.brush->blend;
- if (event->custom == EVT_DATA_TABLET) {
- wmtab = event->customdata;
+ if (event->tablet_data) {
+ wmTabletData *wmtab = event->tablet_data;
tablet = (wmtab->Active != EVT_TABLET_NONE);
pressure = wmtab->Pressure;
if (wmtab->Active == EVT_TABLET_ERASER)
pop->s.blend = IMB_BLEND_ERASE_ALPHA;
}
- else { /* otherwise airbrush becomes 1.0 pressure instantly */
- pressure = pop->prev_pressure ? pop->prev_pressure : 1.0f;
+ else {
+ BLI_assert(fabsf(WM_cursor_pressure(CTX_wm_window(C))) == 1.0f);
+ pressure = 1.0f;
}
if (pop->first) {
@@ -5338,7 +5382,10 @@ static void paint_apply_event(bContext *C, wmOperator *op, wmEvent *event)
/* apply */
paint_apply(C, op, &itemptr);
- pop->prev_pressure = pressure;
+ {
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ ups->pressure_value = pressure;
+ }
}
static int paint_invoke(bContext *C, wmOperator *op, wmEvent *event)
@@ -5349,7 +5396,7 @@ static int paint_invoke(bContext *C, wmOperator *op, wmEvent *event)
MEM_freeN(op->customdata);
return OPERATOR_CANCELLED;
}
-
+
paint_apply_event(C, op, event);
pop = op->customdata;
@@ -5479,6 +5526,16 @@ static void brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata)
glColor4f(brush->add_col[0], brush->add_col[1], brush->add_col[2], alpha);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
+ {
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ /* hrmf, duplicate paint_draw_cursor logic here */
+ if (ups->draw_pressure && BKE_brush_use_size_pressure(scene, brush)) {
+ /* inner at full alpha */
+ glutil_draw_lined_arc(0, (float)(M_PI * 2.0), size * ups->pressure_value, 40);
+ /* outer at half alpha */
+ glColor4f(brush->add_col[0], brush->add_col[1], brush->add_col[2], alpha * 0.5f);
+ }
+ }
glutil_draw_lined_arc(0, (float)(M_PI * 2.0), size, 40);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
@@ -5953,7 +6010,7 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
/* override */
ps.is_texbrush = 0;
- ps.is_airbrush = 1;
+ ps.do_masking = false;
orig_brush_size = BKE_brush_size_get(scene, ps.brush);
BKE_brush_size_set(scene, ps.brush, 32); /* cover the whole image */