diff options
Diffstat (limited to 'source/blender/editors/sculpt_paint/paint_image_proj.c')
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_image_proj.c | 330 |
1 files changed, 250 insertions, 80 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 1303da71435..50480b8aef0 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -7,6 +7,7 @@ */ #include <float.h> +#include <limits.h> #include <math.h> #include <stdio.h> #include <string.h> @@ -35,12 +36,17 @@ #include "IMB_imbuf_types.h" #include "DNA_brush_types.h" +#include "DNA_customdata_types.h" +#include "DNA_defs.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_node_types.h" +#include "DNA_object_enums.h" #include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "BKE_attribute.h" #include "BKE_brush.h" #include "BKE_camera.h" #include "BKE_colorband.h" @@ -61,6 +67,8 @@ #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_screen.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" @@ -76,12 +84,18 @@ #include "GPU_capabilities.h" #include "GPU_init_exit.h" +#include "NOD_shader.h" + +#include "UI_interface.h" +#include "UI_resources.h" + #include "WM_api.h" #include "WM_types.h" #include "RNA_access.h" #include "RNA_define.h" #include "RNA_enum_types.h" +#include "RNA_types.h" #include "IMB_colormanagement.h" @@ -3118,7 +3132,7 @@ static void project_paint_face_init(const ProjPaintState *ps, } } - /* Is this UV visible from the view? - raytrace */ + /* Is this UV visible from the view? - ray-trace */ /* project_paint_PickFace is less complex, use for testing */ // if (project_paint_PickFace(ps, pixelScreenCo, w, &side) == tri_index) { if ((ps->do_occlude == false) || @@ -3208,7 +3222,7 @@ static void project_paint_face_init(const ProjPaintState *ps, float seam_subsection[4][2]; float fac1, fac2; - /* Pixelspace UVs. */ + /* Pixel-space UV's. */ float lt_puv[3][2]; lt_puv[0][0] = lt_uv_pxoffset[0][0] * ibuf->x; @@ -4068,7 +4082,7 @@ typedef struct { static void proj_paint_layer_clone_init(ProjPaintState *ps, ProjPaintLayerClone *layer_clone) { - MLoopUV *mloopuv_clone_base = NULL; + const MLoopUV *mloopuv_clone_base = NULL; /* use clone mtface? */ if (ps->do_layer_clone) { @@ -4478,7 +4492,8 @@ static void project_paint_begin(const bContext *C, } } - /* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */ + /* when using sub-surface or multi-resolution, + * mesh-data arrays are thrown away, we need to keep a copy. */ if (ps->is_shared_user == false) { proj_paint_state_cavity_init(ps); } @@ -6422,6 +6437,17 @@ static const EnumPropertyItem layer_type_items[] = { {0, NULL, 0, NULL, NULL}, }; +static Material *get_or_create_current_material(bContext *C, Object *ob) +{ + Material *ma = BKE_object_material_get(ob, ob->actcol); + if (!ma) { + Main *bmain = CTX_data_main(C); + ma = BKE_material_add(bmain, "Material"); + BKE_object_material_assign(bmain, ob, ma, ob->actcol, BKE_MAT_ASSIGN_USERPREF); + } + return ma; +} + static Image *proj_paint_image_create(wmOperator *op, Main *bmain, bool is_data) { Image *ima; @@ -6459,55 +6485,97 @@ static Image *proj_paint_image_create(wmOperator *op, Main *bmain, bool is_data) return ima; } -static void proj_paint_default_color(wmOperator *op, int type, Material *ma) +static CustomDataLayer *proj_paint_color_attribute_create(wmOperator *op, Object *ob) { - if (RNA_struct_property_is_set(op->ptr, "color")) { - return; + char name[MAX_NAME] = ""; + float color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + eAttrDomain domain = ATTR_DOMAIN_POINT; + eCustomDataType type = CD_PROP_COLOR; + + if (op) { + RNA_string_get(op->ptr, "name", name); + RNA_float_get_array(op->ptr, "color", color); + domain = (eAttrDomain)RNA_enum_get(op->ptr, "domain"); + type = (eCustomDataType)RNA_enum_get(op->ptr, "data_type"); } - bNode *in_node = ntreeFindType(ma->nodetree, SH_NODE_BSDF_PRINCIPLED); - if (in_node == NULL) { - return; + ID *id = (ID *)ob->data; + CustomDataLayer *layer = BKE_id_attribute_new(id, name, type, domain, op->reports); + + if (!layer) { + return NULL; } - float color[4]; + BKE_id_attributes_active_color_set(id, layer); - if (type >= LAYER_BASE_COLOR && type < LAYER_NORMAL) { - /* Copy color from node, so result is unchanged after assigning textures. */ - bNodeSocket *in_sock = nodeFindSocket(in_node, SOCK_IN, layer_type_items[type].name); + if (!BKE_id_attributes_render_color_get(id)) { + BKE_id_attributes_render_color_set(id, layer); + } - switch (in_sock->type) { - case SOCK_FLOAT: { - bNodeSocketValueFloat *socket_data = in_sock->default_value; - copy_v3_fl(color, socket_data->value); - color[3] = 1.0f; - break; + BKE_object_attributes_active_color_fill(ob, color, false); + + return layer; +} + +/** + * Get a default color for the paint slot layer from a material's Principled BSDF. + * + * \param layer_type: The layer type of the paint slot + * \param ma: The material to attempt using as the default color source. + * If this fails or \p ma is null, a default Principled BSDF is used instead. + */ +static void default_paint_slot_color_get(int layer_type, Material *ma, float color[4]) +{ + switch (layer_type) { + case LAYER_BASE_COLOR: + case LAYER_SPECULAR: + case LAYER_ROUGHNESS: + case LAYER_METALLIC: { + bNodeTree *ntree = NULL; + bNode *in_node = ma ? ntreeFindType(ma->nodetree, SH_NODE_BSDF_PRINCIPLED) : NULL; + if (!in_node) { + /* An existing material or Principled BSDF node could not be found. + * Copy default color values from a default Principled BSDF instead. */ + ntree = ntreeAddTree(NULL, "Temporary Shader Nodetree", ntreeType_Shader->idname); + in_node = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_PRINCIPLED); } - case SOCK_VECTOR: - case SOCK_RGBA: { - bNodeSocketValueRGBA *socket_data = in_sock->default_value; - copy_v3_v3(color, socket_data->value); - color[3] = 1.0f; - break; + bNodeSocket *in_sock = nodeFindSocket(in_node, SOCK_IN, layer_type_items[layer_type].name); + switch (in_sock->type) { + case SOCK_FLOAT: { + bNodeSocketValueFloat *socket_data = in_sock->default_value; + copy_v3_fl(color, socket_data->value); + color[3] = 1.0f; + break; + } + case SOCK_VECTOR: + case SOCK_RGBA: { + bNodeSocketValueRGBA *socket_data = in_sock->default_value; + copy_v3_v3(color, socket_data->value); + color[3] = 1.0f; + break; + } + default: + BLI_assert_unreachable(); + rgba_float_args_set(color, 0.0f, 0.0f, 0.0f, 1.0f); + break; } - default: { - return; + /* Cleanup */ + if (ntree) { + ntreeFreeTree(ntree); + MEM_freeN(ntree); } + return; } + case LAYER_NORMAL: + /* Neutral tangent space normal map. */ + rgba_float_args_set(color, 0.5f, 0.5f, 1.0f, 1.0f); + break; + case LAYER_BUMP: + case LAYER_DISPLACEMENT: + /* Neutral displacement and bump map. */ + rgba_float_args_set(color, 0.5f, 0.5f, 0.5f, 1.0f); + break; } - else if (type == LAYER_NORMAL) { - /* Neutral tangent space normal map. */ - rgba_float_args_set(color, 0.5f, 0.5f, 1.0f, 1.0f); - } - else if (ELEM(type, LAYER_BUMP, LAYER_DISPLACEMENT)) { - /* Neutral displacement and bump map. */ - rgba_float_args_set(color, 0.5f, 0.5f, 0.5f, 1.0f); - } - else { - return; - } - - RNA_float_set_array(op->ptr, "color", color); } static bool proj_paint_add_slot(bContext *C, wmOperator *op) @@ -6516,19 +6584,20 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); Material *ma; Image *ima = NULL; + CustomDataLayer *layer = NULL; if (!ob) { return false; } - ma = BKE_object_material_get(ob, ob->actcol); + ma = get_or_create_current_material(C, ob); if (ma) { Main *bmain = CTX_data_main(C); int type = RNA_enum_get(op->ptr, "type"); bool is_data = (type > LAYER_BASE_COLOR); - bNode *imanode; + bNode *new_node; bNodeTree *ntree = ma->nodetree; if (!ntree) { @@ -6538,17 +6607,36 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op) ma->use_nodes = true; - /* try to add an image node */ - imanode = nodeAddStaticNode(C, ntree, SH_NODE_TEX_IMAGE); - - ima = proj_paint_image_create(op, bmain, is_data); - imanode->id = &ima->id; - - nodeSetActive(ntree, imanode); + const ePaintCanvasSource slot_type = ob->mode == OB_MODE_SCULPT ? + (ePaintCanvasSource)RNA_enum_get(op->ptr, + "slot_type") : + PAINT_CANVAS_SOURCE_IMAGE; + + /* Create a new node. */ + switch (slot_type) { + case PAINT_CANVAS_SOURCE_IMAGE: { + new_node = nodeAddStaticNode(C, ntree, SH_NODE_TEX_IMAGE); + ima = proj_paint_image_create(op, bmain, is_data); + new_node->id = &ima->id; + break; + } + case PAINT_CANVAS_SOURCE_COLOR_ATTRIBUTE: { + new_node = nodeAddStaticNode(C, ntree, SH_NODE_ATTRIBUTE); + if ((layer = proj_paint_color_attribute_create(op, ob))) { + BLI_strncpy_utf8( + ((NodeShaderAttribute *)new_node->storage)->name, layer->name, MAX_NAME); + } + break; + } + case PAINT_CANVAS_SOURCE_MATERIAL: + BLI_assert_unreachable(); + return false; + } + nodeSetActive(ntree, new_node); /* Connect to first available principled BSDF node. */ bNode *in_node = ntreeFindType(ntree, SH_NODE_BSDF_PRINCIPLED); - bNode *out_node = imanode; + bNode *out_node = new_node; if (in_node != NULL) { bNodeSocket *out_sock = nodeFindSocket(out_node, SOCK_OUT, "Color"); @@ -6611,6 +6699,11 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op) BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_USER_NEW_IMAGE); WM_event_add_notifier(C, NC_IMAGE | NA_ADDED, ima); } + if (layer) { + BKE_texpaint_slot_refresh_cache(scene, ma, ob); + DEG_id_tag_update(ob->data, ID_RECALC_GEOMETRY); + WM_main_add_notifier(NC_GEOM | ND_DATA, ob->data); + } DEG_id_tag_update(&ntree->id, 0); DEG_id_tag_update(&ma->id, ID_RECALC_SHADING); @@ -6632,25 +6725,8 @@ static int get_texture_layer_type(wmOperator *op, const char *prop_name) return type; } -static Material *get_or_create_current_material(bContext *C, Object *ob) -{ - Material *ma = BKE_object_material_get(ob, ob->actcol); - if (!ma) { - Main *bmain = CTX_data_main(C); - ma = BKE_material_add(bmain, "Material"); - BKE_object_material_assign(bmain, ob, ma, ob->actcol, BKE_MAT_ASSIGN_USERPREF); - } - return ma; -} - static int texture_paint_add_texture_paint_slot_exec(bContext *C, wmOperator *op) { - Object *ob = ED_object_active_context(C); - Material *ma = get_or_create_current_material(C, ob); - - int type = get_texture_layer_type(op, "type"); - proj_paint_default_color(op, type, ma); - if (proj_paint_add_slot(C, op)) { return OPERATOR_FINISHED; } @@ -6671,20 +6747,62 @@ static int texture_paint_add_texture_paint_slot_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - /* Get material and default color to display in the popup. */ Object *ob = ED_object_active_context(C); - Material *ma = get_or_create_current_material(C, ob); + Material *ma = BKE_object_material_get(ob, ob->actcol); int type = get_texture_layer_type(op, "type"); - proj_paint_default_color(op, type, ma); + /* Set default name. */ char imagename[MAX_ID_NAME - 2]; get_default_texture_layer_name_for_object(ob, type, (char *)&imagename, sizeof(imagename)); RNA_string_set(op->ptr, "name", imagename); + /* Set default color. Copy the color from nodes, so it matches the existing material. */ + float color[4]; + default_paint_slot_color_get(type, ma, color); + RNA_float_set_array(op->ptr, "color", color); + return WM_operator_props_dialog_popup(C, op, 300); } +static void texture_paint_add_texture_paint_slot_ui(bContext *C, wmOperator *op) +{ + uiLayout *layout = op->layout; + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); + Object *ob = ED_object_active_context(C); + ePaintCanvasSource slot_type = PAINT_CANVAS_SOURCE_IMAGE; + + if (ob->mode == OB_MODE_SCULPT) { + slot_type = (ePaintCanvasSource)RNA_enum_get(op->ptr, "slot_type"); + uiItemR(layout, op->ptr, "slot_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + } + + uiItemR(layout, op->ptr, "name", 0, NULL, ICON_NONE); + + switch (slot_type) { + case PAINT_CANVAS_SOURCE_IMAGE: { + uiLayout *col = uiLayoutColumn(layout, true); + uiItemR(col, op->ptr, "width", 0, NULL, ICON_NONE); + uiItemR(col, op->ptr, "height", 0, NULL, ICON_NONE); + + uiItemR(layout, op->ptr, "alpha", 0, NULL, ICON_NONE); + uiItemR(layout, op->ptr, "generated_type", 0, NULL, ICON_NONE); + uiItemR(layout, op->ptr, "float", 0, NULL, ICON_NONE); + break; + } + case PAINT_CANVAS_SOURCE_COLOR_ATTRIBUTE: + uiItemR(layout, op->ptr, "domain", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(layout, op->ptr, "data_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + break; + case PAINT_CANVAS_SOURCE_MATERIAL: + BLI_assert_unreachable(); + break; + } + + uiItemR(layout, op->ptr, "color", 0, NULL, ICON_NONE); +} + #define IMA_DEF_NAME N_("Untitled") void PAINT_OT_add_texture_paint_slot(wmOperatorType *ot) @@ -6692,40 +6810,92 @@ void PAINT_OT_add_texture_paint_slot(wmOperatorType *ot) PropertyRNA *prop; static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + static const EnumPropertyItem slot_type_items[3] = { + {PAINT_CANVAS_SOURCE_IMAGE, "IMAGE", 0, "Image", ""}, + {PAINT_CANVAS_SOURCE_COLOR_ATTRIBUTE, "COLOR_ATTRIBUTE", 0, "Color Attribute", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem domain_items[3] = { + {ATTR_DOMAIN_POINT, "POINT", 0, "Vertex", ""}, + {ATTR_DOMAIN_CORNER, "CORNER", 0, "Face Corner", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem attribute_type_items[3] = { + {CD_PROP_COLOR, "COLOR", 0, "Color", ""}, + {CD_PROP_BYTE_COLOR, "BYTE_COLOR", 0, "Byte Color", ""}, + {0, NULL, 0, NULL, NULL}, + }; + /* identifiers */ - ot->name = "Add Texture Paint Slot"; - ot->description = "Add a texture paint slot"; + ot->name = "Add Paint Slot"; + ot->description = "Add a paint slot"; ot->idname = "PAINT_OT_add_texture_paint_slot"; /* api callbacks */ ot->invoke = texture_paint_add_texture_paint_slot_invoke; ot->exec = texture_paint_add_texture_paint_slot_exec; ot->poll = ED_operator_object_active_editable_mesh; + ot->ui = texture_paint_add_texture_paint_slot_ui; /* flags */ ot->flag = OPTYPE_UNDO; - /* properties */ - prop = RNA_def_enum(ot->srna, "type", layer_type_items, 0, "Type", "Merge method to use"); + /* Shared Properties */ + prop = RNA_def_enum(ot->srna, + "type", + layer_type_items, + 0, + "Material Layer Type", + "Material layer type of new paint slot"); RNA_def_property_flag(prop, PROP_HIDDEN); - RNA_def_string(ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image data-block name"); - prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384); - RNA_def_property_subtype(prop, PROP_PIXEL); - prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384); - RNA_def_property_subtype(prop, PROP_PIXEL); + + prop = RNA_def_enum( + ot->srna, "slot_type", slot_type_items, 0, "Slot Type", "Type of new paint slot"); + + prop = RNA_def_string( + ot->srna, "name", IMA_DEF_NAME, MAX_NAME, "Name", "Name for new paint slot source"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_float_color( ot->srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f); RNA_def_property_subtype(prop, PROP_COLOR_GAMMA); RNA_def_property_float_array_default(prop, default_color); + + /* Image Properties */ + prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384); + RNA_def_property_subtype(prop, PROP_PIXEL); + + prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384); + RNA_def_property_subtype(prop, PROP_PIXEL); + RNA_def_boolean(ot->srna, "alpha", true, "Alpha", "Create an image with an alpha channel"); + RNA_def_enum(ot->srna, "generated_type", rna_enum_image_generated_type_items, IMA_GENTYPE_BLANK, "Generated Type", "Fill the image with a grid for UV map testing"); + RNA_def_boolean( ot->srna, "float", 0, "32-bit Float", "Create image with 32-bit floating-point bit depth"); + + /* Color Attribute Properties */ + RNA_def_enum(ot->srna, + "domain", + domain_items, + ATTR_DOMAIN_POINT, + "Domain", + "Type of element that attribute is stored on"); + + RNA_def_enum(ot->srna, + "data_type", + attribute_type_items, + CD_PROP_COLOR, + "Data Type", + "Type of data stored in attribute"); } static int add_simple_uvs_exec(bContext *C, wmOperator *UNUSED(op)) |