Merging r58475 through r58700 from trunk into soc-2013-depsgraph_mt
[blender.git] / source / blender / editors / sculpt_paint / paint_image_proj.c
index 3dff3c7846ad37f72315bdc917ea161894813541..db55dc271f1f8d6a64d8e3a6c81b84b4d92dbfce 100644 (file)
@@ -245,10 +245,12 @@ typedef struct ProjPaintState {
        float normal_angle_inner;
        float normal_angle_range;       /* difference between normal_angle and normal_angle_inner, for easy access */
 
-       short is_ortho;
+       bool do_face_sel;               /* quick access to (me->editflag & ME_EDIT_PAINT_FACE_SEL) */
+       bool is_ortho;
        bool do_masking;              /* use masking during painting. Some operations such as airbrush may disable */
        bool is_texbrush;              /* only to avoid running  */
-       bool is_maskbrush;
+       bool is_maskbrush;            /* mask brush is applied before masking */
+       bool is_maskbrush_tiled;      /* mask brush is applied after masking */
 #ifndef PROJ_DEBUG_NOSEAMBLEED
        float seam_bleed_px;
 #endif
@@ -264,12 +266,14 @@ typedef struct ProjPaintState {
        Image *reproject_image;
        ImBuf *reproject_ibuf;
 
-
        /* threads */
        int thread_tot;
        int bucketMin[2];
        int bucketMax[2];
        int context_bucket_x, context_bucket_y; /* must lock threads while accessing these */
+
+       /* redraw */
+       bool need_redraw;
 } ProjPaintState;
 
 typedef union pixelPointer {
@@ -1118,6 +1122,44 @@ static void screen_px_from_persp(
        interp_v3_v3v3v3(pixelScreenCo, v1co, v2co, v3co, w);
 }
 
+
+/* same as screen_px_from_persp except we return ortho weights back to the caller.
+ * These weights will be used to determine correct interpolation of uvs in cloned uv layer */
+static void screen_px_from_persp_ortho_weights(
+        float uv[2],
+        float v1co[4], float v2co[4], float v3co[4],  /* screenspace coords */
+        float uv1co[2], float uv2co[2], float uv3co[2],
+        float pixelScreenCo[4],
+        float w[3])
+{
+       float w_int[3];
+       float wtot_inv, wtot;
+       barycentric_weights_v2(uv1co, uv2co, uv3co, uv, w);
+
+       /* re-weight from the 4th coord of each screen vert */
+       w_int[0] = w[0] * v1co[3];
+       w_int[1] = w[1] * v2co[3];
+       w_int[2] = w[2] * v3co[3];
+
+       wtot = w_int[0] + w_int[1] + w_int[2];
+
+       if (wtot > 0.0f) {
+               wtot_inv = 1.0f / wtot;
+               w_int[0] *= wtot_inv;
+               w_int[1] *= wtot_inv;
+               w_int[2] *= wtot_inv;
+       }
+       else {
+               w[0] = w[1] = w[2] =
+               w_int[0] = w_int[1] = w_int[2] = 1.0f / 3.0f;  /* dummy values for zero area face */
+       }
+       /* done re-weighting */
+
+       /* do interpolation based on projected weight */
+       interp_v3_v3v3v3(pixelScreenCo, v1co, v2co, v3co, w_int);
+}
+
+
 static void project_face_pixel(const MTFace *tf_other, ImBuf *ibuf_other, const float w[3],
                                int side, unsigned char rgba_ub[4], float rgba_f[4])
 {
@@ -2165,6 +2207,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
        float uv_clip[8][2];
        int uv_clip_tot;
        const short is_ortho = ps->is_ortho;
+       const short is_clone_other = ((ps->brush->imagepaint_tool == PAINT_TOOL_CLONE) && ps->dm_mtface_clone);
        const short do_backfacecull = ps->do_backfacecull;
        const short do_clip = ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0;
 
@@ -2188,8 +2231,6 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
         * but since the first thing most people try is painting onto a quad- better make it work.
         */
 
-
-
        tf_uv_pxoffset[0][0] = tf->uv[0][0] - xhalfpx;
        tf_uv_pxoffset[0][1] = tf->uv[0][1] - yhalfpx;
 
@@ -2274,7 +2315,8 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
                                                has_x_isect = has_isect = 1;
 
                                                if (is_ortho) screen_px_from_ortho(uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
-                                               else          screen_px_from_persp(uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
+                                               else if (is_clone_other) screen_px_from_persp_ortho_weights(uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
+                                               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 || do_3d_mapping) {
@@ -2768,22 +2810,32 @@ static void project_paint_begin(ProjPaintState *ps)
        Image *tpage_last = NULL, *tpage;
 
        /* Face vars */
+       MPoly *mpoly_orig;
        MFace *mf;
        MTFace *tf;
 
        int a, i; /* generic looping vars */
        int image_index = -1, face_index;
+
+       /* double lookup */
+       const int *index_mf_to_mpoly = NULL;
+       const int *index_mp_to_orig  = NULL;
+
        MVert *mv;
 
        MemArena *arena; /* at the moment this is just ps->arena_mt[0], but use this to show were not multithreading */
 
        const int diameter = 2 * BKE_brush_size_get(ps->scene, ps->brush);
 
+       bool reset_threads = false;
+
        /* ---- end defines ---- */
 
        if (ps->source == PROJ_SRC_VIEW)
                ED_view3d_clipping_local(ps->rv3d, ps->ob->obmat);  /* faster clipping lookups */
 
+       ps->do_face_sel = ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PAINT_FACE_SEL) != 0);
+
        /* paint onto the derived mesh */
 
        /* Workaround for subsurf selection, try the display mesh first */
@@ -2792,12 +2844,17 @@ static void project_paint_begin(ProjPaintState *ps)
                ps->dm = mesh_create_derived_render(ps->scene, ps->ob, ps->scene->customdata_mask | CD_MASK_MTFACE);
                ps->dm_release = TRUE;
        }
-       else if (ps->ob->derivedFinal && CustomData_has_layer(&ps->ob->derivedFinal->faceData, CD_MTFACE)) {
+       else if (ps->ob->derivedFinal &&
+                CustomData_has_layer(&ps->ob->derivedFinal->faceData, CD_MTFACE) &&
+                (ps->do_face_sel == false || CustomData_has_layer(&ps->ob->derivedFinal->polyData, CD_ORIGINDEX)))
+       {
                ps->dm = ps->ob->derivedFinal;
                ps->dm_release = FALSE;
        }
        else {
-               ps->dm = mesh_get_derived_final(ps->scene, ps->ob, ps->scene->customdata_mask | CD_MASK_MTFACE);
+               ps->dm = mesh_get_derived_final(
+                            ps->scene, ps->ob,
+                            ps->scene->customdata_mask | CD_MASK_MTFACE | (ps->do_face_sel ? CD_ORIGINDEX : 0));
                ps->dm_release = TRUE;
        }
 
@@ -2817,6 +2874,20 @@ static void project_paint_begin(ProjPaintState *ps)
        ps->dm_totvert = ps->dm->getNumVerts(ps->dm);
        ps->dm_totface = ps->dm->getNumTessFaces(ps->dm);
 
+       if (ps->do_face_sel) {
+               index_mf_to_mpoly = ps->dm->getTessFaceDataArray(ps->dm, CD_ORIGINDEX);
+               index_mp_to_orig  = ps->dm->getPolyDataArray(ps->dm, CD_ORIGINDEX);
+               if (index_mf_to_mpoly == NULL) {
+                       index_mp_to_orig = NULL;
+               }
+               else {
+                       mpoly_orig = ((Mesh *)ps->ob->data)->mpoly;
+               }
+       }
+       else {
+               mpoly_orig = NULL;
+       }
+
        /* use clone mtface? */
 
 
@@ -2824,20 +2895,19 @@ static void project_paint_begin(ProjPaintState *ps)
         * this avoids re-generating the derived mesh just to get the new index */
        if (ps->do_layer_clone) {
                //int layer_num = CustomData_get_clone_layer(&ps->dm->faceData, CD_MTFACE);
-               int layer_num = CustomData_get_clone_layer(&((Mesh *)ps->ob->data)->fdata, CD_MTFACE);
+               int layer_num = CustomData_get_clone_layer(&((Mesh *)ps->ob->data)->pdata, CD_MTEXPOLY);
                if (layer_num != -1)
                        ps->dm_mtface_clone = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num);
 
                if (ps->dm_mtface_clone == NULL || ps->dm_mtface_clone == ps->dm_mtface) {
                        ps->do_layer_clone = FALSE;
                        ps->dm_mtface_clone = NULL;
-                       printf("ACK!\n");
                }
        }
 
        if (ps->do_layer_stencil) {
                //int layer_num = CustomData_get_stencil_layer(&ps->dm->faceData, CD_MTFACE);
-               int layer_num = CustomData_get_stencil_layer(&((Mesh *)ps->ob->data)->fdata, CD_MTFACE);
+               int layer_num = CustomData_get_stencil_layer(&((Mesh *)ps->ob->data)->pdata, CD_MTEXPOLY);
                if (layer_num != -1)
                        ps->dm_mtface_stencil = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num);
 
@@ -2927,8 +2997,8 @@ static void project_paint_begin(ProjPaintState *ps)
                        }
 
                        /* same as #ED_view3d_ob_project_mat_get */
-                       mult_m4_m4m4(vmat, viewmat, ps->ob->obmat);
-                       mult_m4_m4m4(ps->projectMat, winmat, vmat);
+                       mul_m4_m4m4(vmat, viewmat, ps->ob->obmat);
+                       mul_m4_m4m4(ps->projectMat, winmat, vmat);
                }
 
 
@@ -3024,6 +3094,10 @@ static void project_paint_begin(ProjPaintState *ps)
 
        /* printf("\tscreenspace bucket division x:%d y:%d\n", ps->buckets_x, ps->buckets_y); */
 
+       if (ps->buckets_x > PROJ_BUCKET_RECT_MAX || ps->buckets_y > PROJ_BUCKET_RECT_MAX) {
+               reset_threads = true;
+       }
+
        /* really high values could cause problems since it has to allocate a few
         * (ps->buckets_x*ps->buckets_y) sized arrays  */
        CLAMP(ps->buckets_x, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX);
@@ -3047,12 +3121,13 @@ static void project_paint_begin(ProjPaintState *ps)
         * threads is being able to fill in multiple buckets at once.
         * Only use threads for bigger brushes. */
 
-       if (ps->scene->r.mode & R_FIXED_THREADS) {
-               ps->thread_tot = ps->scene->r.threads;
-       }
-       else {
-               ps->thread_tot = BLI_system_thread_count();
-       }
+       ps->thread_tot = BKE_scene_num_threads(ps->scene);
+
+       /* workaround for #35057, disable threading if diameter is less than is possible for
+        * optimum bucket number generation */
+       if (reset_threads)
+               ps->thread_tot = 1;
+
        for (a = 0; a < ps->thread_tot; a++) {
                ps->arena_mt[a] = BLI_memarena_new(1 << 16, "project paint arena");
        }
@@ -3082,8 +3157,8 @@ static void project_paint_begin(ProjPaintState *ps)
                }
        }
 
-
        for (face_index = 0, tf = ps->dm_mtface, mf = ps->dm_mface; face_index < ps->dm_totface; mf++, tf++, face_index++) {
+               bool is_face_sel;
 
 #ifndef PROJ_DEBUG_NOSEAMBLEED
                /* add face user if we have bleed enabled, set the UV seam flags later */
@@ -3098,10 +3173,23 @@ static void project_paint_begin(ProjPaintState *ps)
                }
 #endif
 
-               tpage = project_paint_face_image(ps, ps->dm_mtface, face_index);
-
-               if (tpage && ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PAINT_FACE_SEL) == 0 || mf->flag & ME_FACE_SEL)) {
+               if (ps->do_face_sel) {
+                       int orig_index;
+                       if (index_mp_to_orig && ((orig_index = DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig,
+                                                                                       face_index))) != ORIGINDEX_NONE)
+                       {
+                               MPoly *mp = &mpoly_orig[orig_index];
+                               is_face_sel = ((mp->flag & ME_FACE_SEL) != 0);
+                       }
+                       else {
+                               is_face_sel = ((mf->flag & ME_FACE_SEL) != 0);
+                       }
+               }
+               else {
+                       is_face_sel = true;
+               }
 
+               if (is_face_sel && (tpage = project_paint_face_image(ps, ps->dm_mtface, face_index))) {
                        float *v1coSS, *v2coSS, *v3coSS, *v4coSS = NULL;
 
                        v1coSS = ps->screenCoords[mf->v1];
@@ -3210,7 +3298,7 @@ static void project_paint_begin(ProjPaintState *ps)
        BLI_linklist_free(image_LinkList, NULL);
 }
 
-static void paint_proj_begin_clone(ProjPaintState *ps, const int mouse[2])
+static void paint_proj_begin_clone(ProjPaintState *ps, const float mouse[2])
 {
        /* setup clone offset */
        if (ps->tool == PAINT_TOOL_CLONE) {
@@ -3526,7 +3614,7 @@ static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, floa
                clone_rgba[0] = clone_pt[0];
                clone_rgba[1] = clone_pt[1];
                clone_rgba[2] = clone_pt[2];
-               clone_rgba[3] = clone_pt[3] * mask;
+               clone_rgba[3] = (unsigned char)(clone_pt[3] * mask);
 
                if (ps->do_masking) {
                        IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch, clone_rgba, ps->blend);
@@ -3673,7 +3761,7 @@ static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, const
        }
 
        rgb_float_to_uchar(rgba_ub, rgb);
-       rgba_ub[3] = 255 * mask;
+       rgba_ub[3] = FTOCHAR(mask);
 
        if (ps->do_masking) {
                IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch, rgba_ub, ps->blend);
@@ -3795,6 +3883,7 @@ static void *do_projectpaint_thread(void *ph_v)
                                                float mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
 
                                                straight_uchar_to_premul_float(newColor_f, projPixel->newColor.ch);
+                                               IMB_colormanagement_colorspace_to_scene_linear_v4(newColor_f, TRUE, ps->reproject_ibuf->rect_colorspace);
                                                mul_v4_v4fl(newColor_f, newColor_f, mask);
 
                                                blend_color_mix_float(projPixel->pixel.f_pt,  projPixel->origColor.f,
@@ -3843,7 +3932,14 @@ static void *do_projectpaint_thread(void *ph_v)
                                                         * and never exceeds it, which gives nice smooth results. */
                                                        float mask_accum = projPixel->mask_accum;
 
-                                                       mask = mask_accum + (brush_alpha * 65535.0f - mask_accum) * mask;
+                                                       if (ps->is_maskbrush) {
+                                                               float texmask = BKE_brush_sample_masktex(ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool);
+                                                               CLAMP(texmask, 0.0f, 1.0f);
+                                                               mask = mask_accum + (brush_alpha * texmask * 65535.0f - mask_accum) * mask;
+                                                       }
+                                                       else {
+                                                               mask = mask_accum + (brush_alpha * 65535.0f - mask_accum) * mask;
+                                                       }
                                                        mask_short = (unsigned short)mask;
 
                                                        if (mask_short > projPixel->mask_accum) {
@@ -3855,8 +3951,14 @@ static void *do_projectpaint_thread(void *ph_v)
                                                                continue;
                                                        }
                                                }
-                                               else
+                                               else {
                                                        mask *= brush_alpha;
+                                                       if (ps->is_maskbrush) {
+                                                               float texmask = BKE_brush_sample_masktex(ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool);
+                                                               CLAMP(texmask, 0.0f, 1.0f);
+                                                               mask *= texmask;
+                                                       }
+                                               }
 
                                                if (ps->is_texbrush) {
                                                        MTex *mtex = &brush->mtex;
@@ -3879,7 +3981,7 @@ static void *do_projectpaint_thread(void *ph_v)
                                                        mask *= texrgba[3];
                                                }
 
-                                               if (ps->is_maskbrush) {
+                                               if (ps->is_maskbrush_tiled) {
                                                        mask *= BKE_brush_sample_masktex(ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool);
                                                }
 
@@ -4048,43 +4150,36 @@ static int project_paint_op(void *state, const float lastpos[2], const float pos
 }
 
 
-int paint_proj_stroke(bContext *C, void *pps, const int prevmval_i[2], const int mval_i[2])
+void paint_proj_stroke(bContext *C, void *pps, const float prev_pos[2], const float pos[2])
 {
        ProjPaintState *ps = pps;
-       int a, redraw;
-       float pos[2], prev_pos[2];
-
-       pos[0] = (float)(mval_i[0]);
-       pos[1] = (float)(mval_i[1]);
-
-       prev_pos[0] = (float)(prevmval_i[0]);
-       prev_pos[1] = (float)(prevmval_i[1]);
+       int a;
 
        /* clone gets special treatment here to avoid going through image initialization */
        if (ps->tool == PAINT_TOOL_CLONE && ps->mode == BRUSH_STROKE_INVERT) {
                Scene *scene = ps->scene;
                View3D *v3d = ps->v3d;
                float *cursor = give_cursor(scene, v3d);
+               int mval_i[2] = {(int)pos[0], (int)pos[1]};
 
                view3d_operator_needs_opengl(C);
 
                if (!ED_view3d_autodist(scene, ps->ar, v3d, mval_i, cursor, false))
-                       return 0;
+                       return;
 
                ED_region_tag_redraw(ps->ar);
 
-               return 0;
+               return;
        }
 
-       for (a = 0; a < ps->image_tot; a++)
-               partial_redraw_array_init(ps->projImages[a].partRedrawRect);
-
-       redraw = project_paint_op(ps, prev_pos, pos) ? 1 : 0;
-
-       if (project_image_refresh_tagged(ps))
-               return redraw;
+       /* continue adding to existing partial redraw rects until redraw */
+       if (!ps->need_redraw) {
+               for (a = 0; a < ps->image_tot; a++)
+                       partial_redraw_array_init(ps->projImages[a].partRedrawRect);
+       }
 
-       return 0;
+       if (project_paint_op(ps, prev_pos, pos))
+               ps->need_redraw = true;
 }
 
 
@@ -4108,13 +4203,23 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int
                                  (brush->mtex.tex && !ELEM3(brush->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_3D)))
                                 ? false : true;
                ps->is_texbrush = (brush->mtex.tex && brush->imagepaint_tool == PAINT_TOOL_DRAW) ? true : false;
-               ps->is_maskbrush = (brush->mask_mtex.tex) ? true : false;
+               ps->is_maskbrush = false;
+               ps->is_maskbrush_tiled = false;
+               if (brush->mask_mtex.tex) {
+                       if (ELEM(brush->mask_mtex.brush_map_mode, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_TILED)) {
+                               ps->is_maskbrush_tiled = true;
+                       }
+                       else {
+                               ps->is_maskbrush = true;
+                       }
+               }
        }
        else {
                /* brush may be NULL*/
                ps->do_masking = false;
                ps->is_texbrush = false;
                ps->is_maskbrush = false;
+               ps->is_maskbrush_tiled = false;
        }
 
        /* sizeof(ProjPixel), since we alloc this a _lot_ */
@@ -4164,7 +4269,7 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int
        return;
 }
 
-void *paint_proj_new_stroke(bContext *C, Object *ob, const int mouse[2], int mode)
+void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int mode)
 {
        ProjPaintState *ps = MEM_callocN(sizeof(ProjPaintState), "ProjectionPaintState");
        project_state_init(C, ob, ps, mode);
@@ -4205,6 +4310,28 @@ void *paint_proj_new_stroke(bContext *C, Object *ob, const int mouse[2], int mod
        return ps;
 }
 
+void paint_proj_redraw(const bContext *C, void *pps, bool final)
+{
+       ProjPaintState *ps = pps;
+
+       if (ps->need_redraw) {
+               project_image_refresh_tagged(ps);
+
+               ps->need_redraw = false;
+       }
+       else if (!final) {
+               return;
+       }
+
+       if (final) {
+               /* compositor listener deals with updating */
+               WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, NULL);
+       }
+       else {
+               ED_region_tag_redraw(CTX_wm_region(C));
+       }
+}
+
 void paint_proj_stroke_done(void *pps)
 {
        ProjPaintState *ps = pps;
@@ -4277,6 +4404,7 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
        /* override */
        ps.is_texbrush = false;
        ps.is_maskbrush = false;
+       ps.is_maskbrush_tiled = false;
        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 */