diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py index 046e54d41fc..5c758b6568b 100644 --- a/release/scripts/startup/bl_ui/properties_paint_common.py +++ b/release/scripts/startup/bl_ui/properties_paint_common.py @@ -17,6 +17,7 @@ # ##### END GPL LICENSE BLOCK ##### # +from bpy.types import Menu class UnifiedPaintPanel(): @@ -86,6 +87,18 @@ class UnifiedPaintPanel(): parent.template_color_picker(ptr, prop_name, value_slider=value_slider) +class VIEW3D_MT_tools_projectpaint_clone(Menu): + bl_label = "Clone Layer" + + def draw(self, context): + layout = self.layout + + for i, tex in enumerate(context.active_object.data.uv_textures): + props = layout.operator("wm.context_set_int", text=tex.name, translate=False) + props.data_path = "active_object.data.uv_texture_clone_index" + props.value = i + + def brush_texpaint_common(panel, context, layout, brush, settings, projpaint=False): capabilities = brush.image_paint_capabilities @@ -139,24 +152,38 @@ def brush_texpaint_common(panel, context, layout, brush, settings, projpaint=Fal elif brush.image_tool == 'CLONE': col.separator() if projpaint: - col.prop(settings, "use_clone_layer", text="Clone from paint slot") + if settings.mode == 'MATERIAL': + col.prop(settings, "use_clone_layer", text="Clone from paint slot") + elif settings.mode == 'IMAGE': + col.prop(settings, "use_clone_layer", text="Clone from image/UV map") if settings.use_clone_layer: ob = context.active_object col = layout.column() - if len(ob.material_slots) > 1: - col.label("Materials") - col.template_list("MATERIAL_UL_matslots", "", - ob, "material_slots", - ob, "active_material_index", rows=2) + if settings.mode == 'MATERIAL': + if len(ob.material_slots) > 1: + col.label("Materials") + col.template_list("MATERIAL_UL_matslots", "", + ob, "material_slots", + ob, "active_material_index", rows=2) - mat = ob.active_material - if mat: - col.label("Clone Slot") - col.template_list("TEXTURE_UL_texpaintslots", "", - mat, "texture_paint_images", - mat, "paint_clone_slot", rows=2) + mat = ob.active_material + if mat: + col.label("Clone Slot") + col.template_list("TEXTURE_UL_texpaintslots", "", + mat, "texture_paint_images", + mat, "paint_clone_slot", rows=2) + + elif settings.mode == 'IMAGE': + mesh = ob.data + + clone_text = mesh.uv_texture_clone.name if mesh.uv_texture_clone else "" + col.label("Image") + col.template_ID(settings, "clone_image") + col.label("UV Map") + col.menu("VIEW3D_MT_tools_projectpaint_clone", text=clone_text, translate=False) + else: col.prop(brush, "clone_image", text="Image") diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 59c68fc615d..6b0c5b1e993 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -1026,31 +1026,39 @@ class VIEW3D_PT_slots_projectpaint(View3DPanel, Panel): ob = context.active_object col = layout.column() - if len(ob.material_slots) > 1: - col.label("Materials") - col.template_list("MATERIAL_UL_matslots", "layers", - ob, "material_slots", - ob, "active_material_index", rows=2) + col.label("Painting Mode") + col.prop(settings, "mode", text = "") + col.separator() - mat = ob.active_material - if mat: - col.label("Available Paint Slots") - col.template_list("TEXTURE_UL_texpaintslots", "", - mat, "texture_paint_images", - mat, "paint_active_slot", rows=2) + if settings.mode == 'MATERIAL': + if len(ob.material_slots) > 1: + col.label("Materials") + col.template_list("MATERIAL_UL_matslots", "layers", + ob, "material_slots", + ob, "active_material_index", rows=2) - if (not mat.use_nodes) and (context.scene.render.engine == 'BLENDER_RENDER'): - row = col.row(align=True) - row.operator_menu_enum("paint.add_texture_paint_slot", "type") - row.operator("paint.delete_texture_paint_slot", text="", icon='X') + mat = ob.active_material + if mat: + col.label("Available Paint Slots") + col.template_list("TEXTURE_UL_texpaintslots", "", + mat, "texture_paint_images", + mat, "paint_active_slot", rows=2) - if mat.texture_paint_slots: - slot = mat.texture_paint_slots[mat.paint_active_slot] + if (not mat.use_nodes) and (context.scene.render.engine == 'BLENDER_RENDER'): + row = col.row(align=True) + row.operator_menu_enum("paint.add_texture_paint_slot", "type") + row.operator("paint.delete_texture_paint_slot", text="", icon='X') - col.prop(mat.texture_slots[slot.index], "blend_type") - col.separator() - col.label("UV Map") - col.prop_search(slot, "uv_layer", ob.data, "uv_textures", text="") + if mat.texture_paint_slots: + slot = mat.texture_paint_slots[mat.paint_active_slot] + + col.prop(mat.texture_slots[slot.index], "blend_type") + col.separator() + col.label("UV Map") + col.prop_search(slot, "uv_layer", ob.data, "uv_textures", text="") + + elif settings.mode == 'IMAGE': + col.template_ID(settings, "canvas") col.separator() col.operator("image.save_dirty", text="Save All Images") @@ -1089,7 +1097,6 @@ class VIEW3D_PT_stencil_projectpaint(View3DPanel, Panel): col.label("Image") row = col.row(align=True) - row.operator("image.new", icon='ZOOMIN', text="Add New").texstencil = True; row.template_ID(ipaint, "stencil_image") col.label("Visualization") @@ -1643,18 +1650,6 @@ class VIEW3D_PT_imagepaint_options(View3DPaintPanel): self.unified_paint_settings(col, context) -class VIEW3D_MT_tools_projectpaint_clone(Menu): - bl_label = "Clone Layer" - - def draw(self, context): - layout = self.layout - - for i, tex in enumerate(context.active_object.data.uv_textures): - props = layout.operator("wm.context_set_int", text=tex.name, translate=False) - props.data_path = "active_object.data.uv_texture_clone_index" - props.value = i - - class VIEW3D_MT_tools_projectpaint_stencil(Menu): bl_label = "Mask Layer" diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 50147149b0c..e7500392c81 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -274,8 +274,7 @@ Material *localize_material(Material *ma) if (ma->ramp_col) man->ramp_col = MEM_dupallocN(ma->ramp_col); if (ma->ramp_spec) man->ramp_spec = MEM_dupallocN(ma->ramp_spec); - if (ma->texpaintslot) man->texpaintslot = MEM_dupallocN(man->texpaintslot); - + ma->texpaintslot = NULL; man->preview = NULL; if (ma->nodetree) @@ -1328,9 +1327,16 @@ void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma) if (ma->texpaintslot) { MEM_freeN(ma->texpaintslot); + ma->tot_slots = 0; ma->texpaintslot = NULL; } + if (scene->toolsettings->imapaint.mode == IMAGEPAINT_MODE_IMAGE) { + ma->paint_active_slot = 0; + ma->paint_clone_slot = 0; + return; + } + if (use_nodes || ma->use_nodes) { bNode *node, *active_node; @@ -1342,10 +1348,9 @@ void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma) count++; } - ma->tot_slots = count; - if (count == 0) { ma->paint_active_slot = 0; + ma->paint_clone_slot = 0; return; } ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots"); @@ -1367,10 +1372,9 @@ void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma) } } - ma->tot_slots = count; - if (count == 0) { ma->paint_active_slot = 0; + ma->paint_clone_slot = 0; return; } @@ -1387,6 +1391,8 @@ void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma) } } + ma->tot_slots = count; + if (ma->paint_active_slot >= count) { ma->paint_active_slot = count - 1; } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 8ada7b77bab..b2e49be1a5e 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -5152,6 +5152,14 @@ static void lib_link_scene(FileData *fd, Main *main) sce->toolsettings->imapaint.stencil = newlibadr_us(fd, sce->id.lib, sce->toolsettings->imapaint.stencil); + if (sce->toolsettings->imapaint.clone) + sce->toolsettings->imapaint.clone = + newlibadr_us(fd, sce->id.lib, sce->toolsettings->imapaint.clone); + + if (sce->toolsettings->imapaint.canvas) + sce->toolsettings->imapaint.canvas = + newlibadr_us(fd, sce->id.lib, sce->toolsettings->imapaint.canvas); + sce->toolsettings->skgen_template = newlibadr(fd, sce->id.lib, sce->toolsettings->skgen_template); for (base = sce->base.first; base; base = next) { diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index ea6d56155cc..f596f330534 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -1363,41 +1363,87 @@ void paint_proj_mesh_data_ensure(bContext *C, Object *ob, wmOperator *op) Mesh *me; int layernum; ImagePaintSettings *imapaint = &(CTX_data_tool_settings(C)->imapaint); + bScreen *sc; Scene *scene = CTX_data_scene(C); + Main *bmain = CTX_data_main(C); Brush *br = BKE_paint_brush(&imapaint->paint); - /* no material, add one */ - if (ob->totcol == 0) { - Material *ma = BKE_material_add(CTX_data_main(C), "Material"); - /* no material found, just assign to first slot */ - assign_material(ob, ma, 1, BKE_MAT_ASSIGN_USERPREF); - proj_paint_add_slot(C, ma, NULL); - } - else { - /* there may be material slots but they may be empty, check */ - int i; - - for (i = 1; i < ob->totcol + 1; i++) { - Material *ma = give_current_material(ob, i); - if (ma) { - if (!ma->texpaintslot) { - /* refresh here just in case */ - BKE_texpaint_slot_refresh_cache(scene, ma); - - /* if still no slots, we have to add */ - if (!ma->texpaintslot) - proj_paint_add_slot(C, ma, NULL); + if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) { + /* no material, add one */ + if (ob->totcol == 0) { + Material *ma = BKE_material_add(CTX_data_main(C), "Material"); + /* no material found, just assign to first slot */ + assign_material(ob, ma, 1, BKE_MAT_ASSIGN_USERPREF); + proj_paint_add_slot(C, ma, NULL); + } + else { + /* there may be material slots but they may be empty, check */ + int i; + + for (i = 1; i < ob->totcol + 1; i++) { + Material *ma = give_current_material(ob, i); + if (ma) { + if (!ma->texpaintslot) { + /* refresh here just in case */ + BKE_texpaint_slot_refresh_cache(scene, ma); + + /* if still no slots, we have to add */ + if (!ma->texpaintslot) { + proj_paint_add_slot(C, ma, NULL); + + for (sc = bmain->screen.first; sc; sc = sc->id.next) { + 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; + + ED_space_image_set(sima, scene, scene->obedit, ma->texpaintslot[0].ima); + } + } + } + } + + } + } + } + else { + Material *ma = BKE_material_add(CTX_data_main(C), "Material"); + /* no material found, just assign to first slot */ + assign_material(ob, ma, i, BKE_MAT_ASSIGN_USERPREF); + proj_paint_add_slot(C, ma, NULL); } - } - else { - Material *ma = BKE_material_add(CTX_data_main(C), "Material"); - /* no material found, just assign to first slot */ - assign_material(ob, ma, i, BKE_MAT_ASSIGN_USERPREF); - proj_paint_add_slot(C, ma, NULL); } } } + else if (imapaint->mode == IMAGEPAINT_MODE_IMAGE){ + if (imapaint->canvas == NULL) { + int width; + int height; + Main *bmain = CTX_data_main(C); + float color[4] = {0.0, 0.0, 0.0, 1.0}; + width = 1024; + height = 1024; + imapaint->canvas = BKE_image_add_generated(bmain, width, height, "Canvas", 32, false, IMA_GENTYPE_BLANK, color); + + for (sc = bmain->screen.first; sc; sc = sc->id.next) { + 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; + + ED_space_image_set(sima, scene, scene->obedit, imapaint->canvas); + } + } + } + } + } + } + me = BKE_mesh_from_object(ob); layernum = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY); @@ -1449,7 +1495,8 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op) else { bScreen *sc; Main *bmain = CTX_data_main(C); - Material *ma; + Image *ima = NULL; + ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; /* This has to stay here to regenerate the texture paint * cache in case we are loading a file */ @@ -1457,19 +1504,26 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op) paint_proj_mesh_data_ensure(C, ob, op); - /* set the current material active paint slot on image editor */ - ma = give_current_material(ob, ob->actcol); + /* entering paint mode also sets image to editors */ + if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) { + Material *ma = give_current_material(ob, ob->actcol); /* set the current material active paint slot on image editor */ - if (ma->tot_slots > 0) { - for (sc = bmain->screen.first; sc; sc = sc->id.next) { - 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; - ED_space_image_set(sima, scene, scene->obedit, ma->texpaintslot[ma->paint_active_slot].ima); - } + if (ma->texpaintslot) + ima = ma->texpaintslot[ma->paint_active_slot].ima; + } + else if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) { + ima = imapaint->canvas; + } + + for (sc = bmain->screen.first; sc; sc = sc->id.next) { + 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; + + ED_space_image_set(sima, scene, scene->obedit, ima); } } } diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 9362510a84d..3c6fb5dfe20 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -220,6 +220,8 @@ typedef struct ProjPaintState { MTFace *dm_mtface_stencil; Image *stencil_ima; + Image *canvas_ima; + Image *clone_ima; float stencil_value; /* projection painting only */ @@ -256,6 +258,7 @@ typedef struct ProjPaintState { bool do_layer_stencil; bool do_layer_stencil_inv; bool do_stencil_brush; + bool do_material_slots; bool do_occlude; /* Use raytraced occlusion? - ortherwise will paint right through to the back*/ bool do_backfacecull; /* ignore faces with normals pointing away, skips a lot of raycasts if your normals are correctly flipped */ @@ -368,16 +371,23 @@ static Image *project_paint_face_paint_image(const ProjPaintState *ps, int face_ MFace *mf = ps->dm_mface + face_index; Material *ma = ps->dm->mat[mf->mat_nr]; TexPaintSlot *slot = ma->texpaintslot + ma->paint_active_slot; - return slot ? slot->ima : NULL; + return slot ? slot->ima : ps->canvas_ima; } } - static TexPaintSlot *project_paint_face_clone_slot(const ProjPaintState *ps, int face_index) { MFace *mf = ps->dm_mface + face_index; Material *ma = ps->dm->mat[mf->mat_nr]; - return &ma->texpaintslot[ma->paint_clone_slot]; + return ma->texpaintslot + ma->paint_clone_slot; +} + +static Image *project_paint_face_clone_image(const ProjPaintState *ps, int face_index) +{ + MFace *mf = ps->dm_mface + face_index; + Material *ma = ps->dm->mat[mf->mat_nr]; + TexPaintSlot *slot = ma->texpaintslot + ma->paint_clone_slot; + return slot ? slot->ima : ps->clone_ima; } /* fast projection bucket array lookup, use the safe version for bound checking */ @@ -1466,7 +1476,7 @@ static ProjPixel *project_paint_uvpixel_init( if (ps->tool == PAINT_TOOL_CLONE) { if (ps->dm_mtface_clone) { ImBuf *ibuf_other; - Image *other_tpage = project_paint_face_clone_slot(ps, face_index)->ima; + Image *other_tpage = project_paint_face_clone_image(ps, face_index); const MTFace *tf_other = ps->dm_mtface_clone[face_index]; if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) { @@ -3005,6 +3015,19 @@ static void project_paint_begin(ProjPaintState *ps) if (ps->do_stencil_brush) tf_base = ps->dm_mtface_stencil; } + + if (ps->do_layer_clone) { + int layer_num = CustomData_get_clone_layer(&((Mesh *)ps->ob->data)->pdata, CD_MTEXPOLY); + + if (layer_num != -1) + tf_clone_base = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num); + + if (tf_clone_base == NULL) { + /* get active instead */ + tf_clone_base = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE); + } + + } /* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */ if (ps->dm->type != DM_TYPE_CDDM) { @@ -3291,6 +3314,7 @@ static void project_paint_begin(ProjPaintState *ps) /* all faces should have a valid slot, reassert here */ if (slot == NULL) { tf_base = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE); + tpage = ps->canvas_ima; } else { if (slot != slot_last) { @@ -3302,32 +3326,43 @@ static void project_paint_begin(ProjPaintState *ps) /* don't allow using the same inage for painting and stencilling */ if (slot->ima == ps->stencil_ima) continue; + + tpage = slot->ima; } } + else { + tpage = ps->stencil_ima; + } *tf = tf_base + face_index; if (ps->do_layer_clone) { - slot_clone = project_paint_face_clone_slot(ps, face_index); - /* all faces should have a valid slot, reassert here */ - if (ELEM(slot_clone, NULL, slot)) - continue; - - tf_clone = ps->dm_mtface_clone + face_index; - - if (slot_clone != slot_last_clone) { - if (!slot->uvname || !(tf_clone_base = CustomData_get_layer_named(&ps->dm->faceData, CD_MTFACE, slot_clone->uvname))) - tf_clone_base = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE); - slot_last_clone = slot_clone; + if (ps->do_material_slots) { + slot_clone = project_paint_face_clone_slot(ps, face_index); + /* all faces should have a valid slot, reassert here */ + if (ELEM(slot_clone, NULL, slot)) + continue; } - + else if (ps->clone_ima == ps->canvas_ima) + continue; + + tf_clone = ps->dm_mtface_clone + face_index; + + if (ps->do_material_slots) { + if (slot_clone != slot_last_clone) { + if (!slot->uvname || !(tf_clone_base = CustomData_get_layer_named(&ps->dm->faceData, CD_MTFACE, slot_clone->uvname))) + tf_clone_base = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE); + slot_last_clone = slot_clone; + } + } + *tf_clone = tf_clone_base + face_index; } /* tfbase here should be non-null! */ BLI_assert (tf_base != NULL); - if (is_face_sel && ((slot && (tpage = slot->ima)) || (tpage = project_paint_face_paint_image(ps, face_index)))) { + if (is_face_sel && tpage) { const float *v1coSS, *v2coSS, *v3coSS, *v4coSS = NULL; v1coSS = ps->screenCoords[mf->v1]; @@ -4480,7 +4515,13 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int ps->scene = scene; ps->ob = ob; /* allow override of active object */ + ps->do_material_slots = (settings->imapaint.mode == IMAGEPAINT_MODE_MATERIAL); ps->stencil_ima = settings->imapaint.stencil; + ps->canvas_ima = (!ps->do_material_slots) ? + settings->imapaint.canvas : NULL; + ps->clone_ima = (!ps->do_material_slots) ? + settings->imapaint.clone : NULL; + /* setup projection painting data */ ps->do_backfacecull = (settings->imapaint.flag & IMAGEPAINT_PROJECT_BACKFACE) ? 0 : 1; ps->do_occlude = (settings->imapaint.flag & IMAGEPAINT_PROJECT_XRAY) ? 0 : 1; diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index 0d463172f99..486bf2a5d66 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -312,7 +312,7 @@ static void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, c if (mf.v4) dm->getVert(dm, mf.v4, &mv[3]); - if (!slot->uvname || !(tf_base = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, slot->uvname))) + if (!(slot && slot->uvname && (tf_base = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, slot->uvname)))) tf_base = CustomData_get_layer(&dm->faceData, CD_MTFACE); tf = &tf_base[a]; @@ -428,6 +428,8 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr /* first try getting a colour directly from the mesh faces if possible */ Object *ob = OBACT; bool sample_success = false; + ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; + bool use_material = (imapaint->mode == IMAGEPAINT_MODE_MATERIAL); if (ob) { DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); @@ -446,51 +448,58 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr view3d_operator_needs_opengl(C); if (imapaint_pick_face(&vc, mval, &faceindex, totface)) { - Image *image = imapaint_face_image(dm, faceindex); - - ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL); - if (ibuf && ibuf->rect) { - float uv[2]; - float u, v; - imapaint_pick_uv(scene, ob, faceindex, mval, uv); - sample_success = true; - - u = fmodf(uv[0], 1.0f); - v = fmodf(uv[1], 1.0f); - - if (u < 0.0f) u += 1.0f; - if (v < 0.0f) v += 1.0f; - - u = u * ibuf->x - 0.5f; - v = v * ibuf->y - 0.5f; - - if (ibuf->rect_float) { - float rgba_f[4]; - bilinear_interpolation_color_wrap(ibuf, NULL, rgba_f, u, v); - straight_to_premul_v4(rgba_f); - if (use_palette) { - linearrgb_to_srgb_v3_v3(color->rgb, rgba_f); + Image *image; + + if (use_material) + image = imapaint_face_image(dm, faceindex); + else + image = imapaint->canvas; + + if (image) { + ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL); + if (ibuf && ibuf->rect) { + float uv[2]; + float u, v; + imapaint_pick_uv(scene, ob, faceindex, mval, uv); + sample_success = true; + + u = fmodf(uv[0], 1.0f); + v = fmodf(uv[1], 1.0f); + + if (u < 0.0f) u += 1.0f; + if (v < 0.0f) v += 1.0f; + + u = u * ibuf->x - 0.5f; + v = v * ibuf->y - 0.5f; + + if (ibuf->rect_float) { + float rgba_f[4]; + bilinear_interpolation_color_wrap(ibuf, NULL, rgba_f, u, v); + straight_to_premul_v4(rgba_f); + if (use_palette) { + linearrgb_to_srgb_v3_v3(color->rgb, rgba_f); + } + else { + linearrgb_to_srgb_v3_v3(rgba_f, rgba_f); + BKE_brush_color_set(scene, br, rgba_f); + } } else { - linearrgb_to_srgb_v3_v3(rgba_f, rgba_f); - BKE_brush_color_set(scene, br, rgba_f); - } - } - else { - unsigned char rgba[4]; - bilinear_interpolation_color_wrap(ibuf, rgba, NULL, u, v); - if (use_palette) { - rgb_uchar_to_float(color->rgb, rgba); - } - else { - float rgba_f[3]; - rgb_uchar_to_float(rgba_f, rgba); - BKE_brush_color_set(scene, br, rgba_f); + unsigned char rgba[4]; + bilinear_interpolation_color_wrap(ibuf, rgba, NULL, u, v); + if (use_palette) { + rgb_uchar_to_float(color->rgb, rgba); + } + else { + float rgba_f[3]; + rgb_uchar_to_float(rgba_f, rgba); + BKE_brush_color_set(scene, br, rgba_f); + } } } + + BKE_image_release_ibuf(image, ibuf, NULL); } - - BKE_image_release_ibuf(image, ibuf, NULL); } } dm->release(dm); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index f402f1cb4c8..0a3713a41e4 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1907,7 +1907,6 @@ static int image_new_exec(bContext *C, wmOperator *op) char *name = _name; float color[4]; int width, height, floatbuf, gen_type, alpha; - bool stencil; /* retrieve state */ sima = CTX_wm_space_image(C); @@ -1927,7 +1926,6 @@ static int image_new_exec(bContext *C, wmOperator *op) gen_type = RNA_enum_get(op->ptr, "generated_type"); RNA_float_get_array(op->ptr, "color", color); alpha = RNA_boolean_get(op->ptr, "alpha"); - stencil = RNA_boolean_get(op->ptr, "texstencil"); if (!alpha) color[3] = 1.0f; @@ -1960,13 +1958,6 @@ static int image_new_exec(bContext *C, wmOperator *op) tex->ima = ima; ED_area_tag_redraw(CTX_wm_area(C)); } - else if (stencil) { - ImagePaintSettings *imapaint = &(CTX_data_tool_settings(C)->imapaint); - - if (imapaint->stencil) - id_us_min(&imapaint->stencil->id); - imapaint->stencil = ima; - } } BKE_image_signal(ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_USER_NEW_IMAGE); diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c index e571584a10f..dd9b9dea02a 100644 --- a/source/blender/editors/space_view3d/drawmesh.c +++ b/source/blender/editors/space_view3d/drawmesh.c @@ -212,7 +212,8 @@ static Material *give_current_material_or_def(Object *ob, int matnr) static struct TextureDrawState { Object *ob; - Image *stencil; + Image *stencil; /* texture painting stencil */ + Image *canvas; /* texture painting canvas, for image mode */ bool stencil_invert; bool use_game_mat; int is_lit, is_tex; @@ -221,7 +222,8 @@ static struct TextureDrawState { unsigned char obcol[4]; float stencil_col[4]; bool is_texpaint; -} Gtexdraw = {NULL, NULL, false, false, 0, 0, 0, false, {0, 0, 0, 0}, {0.0f, 0.0f, 0.0f, 1.0f}, false}; + bool texpaint_material; /* use material slots for texture painting */ +} Gtexdraw = {NULL, NULL, NULL, false, false, 0, 0, 0, false, {0, 0, 0, 0}, {0.0f, 0.0f, 0.0f, 1.0f}, false, false}; static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material *ma, struct TextureDrawState gtexdraw) { @@ -280,7 +282,10 @@ static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material * alphablend = GPU_BLEND_ALPHA; } else if (texpaint && ma) { - ima = ma->texpaintslot ? ma->texpaintslot[ma->paint_active_slot].ima : NULL; + if (gtexdraw.texpaint_material) + ima = ma->texpaintslot ? ma->texpaintslot[ma->paint_active_slot].ima : NULL; + else + ima = gtexdraw.canvas; } else textured = 0; @@ -394,6 +399,8 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O Gtexdraw.stencil_invert = ((imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) != 0); Gtexdraw.is_texpaint = (ob->mode == OB_MODE_TEXTURE_PAINT); copy_v3_v3(Gtexdraw.stencil_col, imapaint->stencil_col); + Gtexdraw.texpaint_material = (imapaint->mode == IMAGEPAINT_MODE_MATERIAL); + Gtexdraw.canvas = (Gtexdraw.texpaint_material) ? NULL : imapaint->canvas; Gtexdraw.is_tex = is_tex; /* load the stencil texture here */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index d7bc8e56e38..c8b8e4d52a4 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -841,12 +841,14 @@ typedef struct ImagePaintSettings { short seam_bleed, normal_angle; short screen_grab_size[2]; /* capture size for re-projection */ - int pad1; + int mode; /* mode used for texture painting */ - void *paintcursor; /* wm handle */ - struct Image *stencil; /* workaround until we support true layer masks */ + void *paintcursor; /* wm handle */ + struct Image *stencil; /* workaround until we support true layer masks */ + struct Image *clone; /* clone layer for image mode for projective texture painting */ + struct Image *canvas; /* canvas when the explicit system is used for painting */ float stencil_col[3]; - float pad2; + float pad1; } ImagePaintSettings; /* ------------------------------------------- */ @@ -1708,6 +1710,11 @@ typedef enum SculptFlags { SCULPT_DYNTOPO_DETAIL_CONSTANT = (1 << 13) } SculptFlags; +typedef enum ImagePaintMode { + IMAGEPAINT_MODE_MATERIAL, /* detect texture paint slots from the material */ + IMAGEPAINT_MODE_IMAGE, /* select texture paint image directly */ +} ImagePaintMode; + #if (DNA_DEPRECATED_GCC_POISON == 1) #pragma GCC poison SCULPT_SYMM_X SCULPT_SYMM_Y SCULPT_SYMM_Z SCULPT_SYMMETRY_FEATHER #endif diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index c395b963d48..37b6947cfac 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -181,7 +181,6 @@ static void rna_Material_active_paint_texture_index_update(Main *bmain, Scene *s bScreen *sc; Material *ma = ptr->id.data; - if (ma->use_nodes && ma->nodetree && BKE_scene_use_new_shading_nodes(scene)) { struct bNode *node; int index = 0; diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index af6cf493f1e..c4b5461dece 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -34,8 +34,13 @@ #include "DNA_ID.h" #include "DNA_scene_types.h" #include "DNA_brush_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" #include "BKE_paint.h" +#include "BKE_material.h" + +#include "ED_image.h" #include "WM_api.h" #include "WM_types.h" @@ -286,11 +291,44 @@ static void rna_Paint_brush_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Po WM_main_add_notifier(NC_BRUSH | NA_EDITED, br); } -static void rna_ImaPaint_stencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) +static void rna_ImaPaint_viewport_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) { /* not the best solution maybe, but will refresh the 3D viewport */ WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); } + +static void rna_ImaPaint_mode_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr)) +{ + Object *ob = OBACT; + + /* of course we need to invalidate here */ + BKE_texpaint_slots_refresh_object(scene, ob); + + /* we assume that changing the current mode will invalidate the uv layers so we need to tag an update */ + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_main_add_notifier(NC_GEOM | ND_DATA, &ob->id); +} + +static void rna_ImaPaint_canvas_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr)) +{ + bScreen *sc; + Image *ima = scene->toolsettings->imapaint.canvas; + + for (sc = bmain->screen.first; sc; sc = sc->id.next) { + 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; + ED_space_image_set(sima, scene, scene->obedit, ima); + } + } + } + } + + WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); +} #else static void rna_def_palettecolor(BlenderRNA *brna) @@ -571,6 +609,14 @@ static void rna_def_image_paint(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; + + static EnumPropertyItem paint_type_items[] = { + {IMAGEPAINT_MODE_MATERIAL, "MATERIAL", 0, + "Material", "Detect image slots from the material"}, + {IMAGEPAINT_MODE_IMAGE, "IMAGE", 0, + "Image", "Set image for texture painting directly"}, + {0, NULL, 0, NULL, NULL} + }; srna = RNA_def_struct(brna, "ImagePaint", "Paint"); RNA_def_struct_sdna(srna, "ImagePaintSettings"); @@ -596,24 +642,35 @@ static void rna_def_image_paint(BlenderRNA *brna) prop = RNA_def_property(srna, "use_stencil_layer", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMAGEPAINT_PROJECT_LAYER_STENCIL); RNA_def_property_ui_text(prop, "Stencil Layer", "Set the mask layer from the UV map buttons"); - RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_stencil_update"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_viewport_update"); prop = RNA_def_property(srna, "invert_stencil", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMAGEPAINT_PROJECT_LAYER_STENCIL_INV); RNA_def_property_ui_text(prop, "Invert", "Invert the stencil layer"); - RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_stencil_update"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_viewport_update"); prop = RNA_def_property(srna, "stencil_image", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "stencil"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Stencil Image", "Image used as stencil"); - RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_stencil_update"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_viewport_update"); + prop = RNA_def_property(srna, "canvas", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Canvas", "Image used as canvas"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_canvas_update"); + + prop = RNA_def_property(srna, "clone_image", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "clone"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Clone Image", "Image used as clone source"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + prop = RNA_def_property(srna, "stencil_color", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_range(prop, 0.0, 1.0); RNA_def_property_float_sdna(prop, NULL, "stencil_col"); RNA_def_property_ui_text(prop, "Stencil Color", "Stencil color in the viewport"); - RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_stencil_update"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_viewport_update"); prop = RNA_def_property(srna, "use_clone_layer", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMAGEPAINT_PROJECT_LAYER_CLONE); @@ -634,6 +691,11 @@ static void rna_def_image_paint(BlenderRNA *brna) prop = RNA_def_int_array(srna, "screen_grab_size", 2, NULL, 0, 0, "screen_grab_size", "Size to capture the image for re-projecting", 0, 0); RNA_def_property_range(prop, 512, 16384); + + prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, paint_type_items); + RNA_def_property_ui_text(prop, "Mode", "Mode of operation for projection painting"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_mode_update"); } static void rna_def_particle_edit(BlenderRNA *brna)