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:
authorJeroen Bakker <jbakker>2022-04-08 17:37:35 +0300
committerJeroen Bakker <jeroen@blender.org>2022-04-08 17:42:50 +0300
commit8b7cd1ed2a17e40661101eea4adae99e8e3d02e9 (patch)
tree8c3f1f2a14d699fad0367ce529254f2efb517acf /source/blender/blenkernel
parent63d2980efa2fb170b471e4905ec81cd1472e5268 (diff)
Painting: Canvas switcher for painting brushes/tools.
This patch adds color attributes to TexPaintSlot. This allows an easier selection when painting color attributes. Previously when selecting a paint tool the user had to start a stroke, before the UI reflected the correct TexPaintSlot. Now when switching the slot the active tool is checked and immediate the UI is drawn correctly. In the future the canvas selector will also be used to select an image or image texture node to paint on. Basic implementation has already been done inside this patch. A limitation of this patch is that is isn't possible anymore to rename images directly from the selection panel. This is currently allowed in master. But as CustomDataLayers aren't ID fields and not owned by the material supporting this wouldn't be easy. {F12953989} In the future we should update the create slot operator to also include color attributes. Sources could also be extended to use other areas of the object that use image textures (particles, geom nodes, etc... ). Reviewed By: brecht Maniphest Tasks: T96709 Differential Revision: https://developer.blender.org/D14455
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_attribute.h1
-rw-r--r--source/blender/blenkernel/BKE_material.h4
-rw-r--r--source/blender/blenkernel/BKE_node.h8
-rw-r--r--source/blender/blenkernel/BKE_paint.h8
-rw-r--r--source/blender/blenkernel/intern/attribute.c15
-rw-r--r--source/blender/blenkernel/intern/material.c135
-rw-r--r--source/blender/blenkernel/intern/node.cc20
-rw-r--r--source/blender/blenkernel/intern/paint.c7
8 files changed, 153 insertions, 45 deletions
diff --git a/source/blender/blenkernel/BKE_attribute.h b/source/blender/blenkernel/BKE_attribute.h
index c5aca6a9373..62469a28eb1 100644
--- a/source/blender/blenkernel/BKE_attribute.h
+++ b/source/blender/blenkernel/BKE_attribute.h
@@ -122,6 +122,7 @@ struct CustomDataLayer *BKE_id_attributes_active_color_get(const struct ID *id);
void BKE_id_attributes_active_color_set(struct ID *id, struct CustomDataLayer *active_layer);
struct CustomDataLayer *BKE_id_attributes_render_color_get(const struct ID *id);
void BKE_id_attributes_render_color_set(struct ID *id, struct CustomDataLayer *active_layer);
+struct CustomDataLayer *BKE_id_attributes_color_find(const struct ID *id, const char *name);
bool BKE_id_attribute_calc_unique_name(struct ID *id, const char *name, char *outname);
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index 0870a099c76..f38f6afff7e 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -104,7 +104,9 @@ bool BKE_object_material_slot_used(struct Object *object, short actcol);
struct Material *BKE_gpencil_material(struct Object *ob, short act);
struct MaterialGPencilStyle *BKE_gpencil_material_settings(struct Object *ob, short act);
-void BKE_texpaint_slot_refresh_cache(struct Scene *scene, struct Material *ma);
+void BKE_texpaint_slot_refresh_cache(struct Scene *scene,
+ struct Material *ma,
+ const struct Object *ob);
void BKE_texpaint_slots_refresh_object(struct Scene *scene, struct Object *ob);
struct bNode *BKE_texpaint_slot_material_find_node(struct Material *ma, short texpaint_slot);
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index fa199300780..23f14f9be9d 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -770,6 +770,14 @@ void nodeClearActive(struct bNodeTree *ntree);
* Two active flags, ID nodes have special flag for buttons display.
*/
struct bNode *nodeGetActiveTexture(struct bNodeTree *ntree);
+struct bNode *nodeGetActivePaintCanvas(struct bNodeTree *ntree);
+
+/**
+ * @brief Does the given node supports the sub active flag.
+ *
+ * @param sub_active The active flag to check. NODE_ACTIVE_TEXTURE/NODE_ACTIVE_PAINT_CANVAS
+ */
+bool nodeSupportsActiveFlag(const struct bNode *node, int sub_active);
int nodeSocketIsHidden(const struct bNodeSocket *sock);
void nodeSetSocketAvailability(struct bNodeTree *ntree,
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 5633c476dc1..1b296277b8f 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -641,6 +641,14 @@ typedef struct SculptSession {
*/
char needs_flush_to_id;
+ /**
+ * Some tools follows the shading chosen by the last used tool canvas.
+ * When not set the viewport shading color would be used.
+ *
+ * NOTE: This setting is temporarily until paint mode is added.
+ */
+ bool sticky_shading_color;
+
} SculptSession;
void BKE_sculptsession_free(struct Object *ob);
diff --git a/source/blender/blenkernel/intern/attribute.c b/source/blender/blenkernel/intern/attribute.c
index c3d4eb72c0d..d8c7c3c6dd7 100644
--- a/source/blender/blenkernel/intern/attribute.c
+++ b/source/blender/blenkernel/intern/attribute.c
@@ -617,6 +617,21 @@ void BKE_id_attributes_render_color_set(ID *id, CustomDataLayer *active_layer)
id, active_layer, CD_FLAG_COLOR_RENDER, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
}
+CustomDataLayer *BKE_id_attributes_color_find(const ID *id, const char *name)
+{
+ CustomDataLayer *layer = BKE_id_attribute_find(id, name, CD_PROP_COLOR, ATTR_DOMAIN_POINT);
+ if (layer == NULL) {
+ layer = BKE_id_attribute_find(id, name, CD_PROP_COLOR, ATTR_DOMAIN_CORNER);
+ }
+ if (layer == NULL) {
+ layer = BKE_id_attribute_find(id, name, CD_MLOOPCOL, ATTR_DOMAIN_POINT);
+ }
+ if (layer == NULL) {
+ layer = BKE_id_attribute_find(id, name, CD_MLOOPCOL, ATTR_DOMAIN_CORNER);
+ }
+ return layer;
+}
+
void BKE_id_attribute_copy_domains_temp(short id_type,
const CustomData *vdata,
const CustomData *edata,
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 7d01a92e829..bc569956f66 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -43,6 +43,7 @@
#include "BLT_translation.h"
#include "BKE_anim_data.h"
+#include "BKE_attribute.h"
#include "BKE_brush.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
@@ -1347,21 +1348,36 @@ static bNode *nodetree_uv_node_recursive(bNode *node)
return NULL;
}
+/** Bitwise filter for updating paint slots. */
+typedef enum ePaintSlotFilter {
+ PAINT_SLOT_IMAGE = 1 << 0,
+ PAINT_SLOT_COLOR_ATTRIBUTE = 1 << 1,
+} ePaintSlotFilter;
+
typedef bool (*ForEachTexNodeCallback)(bNode *node, void *userdata);
static bool ntree_foreach_texnode_recursive(bNodeTree *nodetree,
ForEachTexNodeCallback callback,
- void *userdata)
+ void *userdata,
+ ePaintSlotFilter slot_filter)
{
+ const bool do_image_nodes = (slot_filter & PAINT_SLOT_IMAGE) != 0;
+ const bool do_color_attributes = (slot_filter & PAINT_SLOT_COLOR_ATTRIBUTE) != 0;
LISTBASE_FOREACH (bNode *, node, &nodetree->nodes) {
- if (node->typeinfo->nclass == NODE_CLASS_TEXTURE &&
+ if (do_image_nodes && node->typeinfo->nclass == NODE_CLASS_TEXTURE &&
node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) {
if (!callback(node, userdata)) {
return false;
}
}
+ if (do_color_attributes && node->typeinfo->type == SH_NODE_ATTRIBUTE) {
+ if (!callback(node, userdata)) {
+ return false;
+ }
+ }
else if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id) {
/* recurse into the node group and see if it contains any textures */
- if (!ntree_foreach_texnode_recursive((bNodeTree *)node->id, callback, userdata)) {
+ if (!ntree_foreach_texnode_recursive(
+ (bNodeTree *)node->id, callback, userdata, slot_filter)) {
return false;
}
}
@@ -1375,16 +1391,17 @@ static bool count_texture_nodes_cb(bNode *UNUSED(node), void *userdata)
return true;
}
-static int count_texture_nodes_recursive(bNodeTree *nodetree)
+static int count_texture_nodes_recursive(bNodeTree *nodetree, ePaintSlotFilter slot_filter)
{
int tex_nodes = 0;
- ntree_foreach_texnode_recursive(nodetree, count_texture_nodes_cb, &tex_nodes);
+ ntree_foreach_texnode_recursive(nodetree, count_texture_nodes_cb, &tex_nodes, slot_filter);
return tex_nodes;
}
struct FillTexPaintSlotsData {
bNode *active_node;
+ const Object *ob;
Material *ma;
int index;
int slot_len;
@@ -1402,21 +1419,45 @@ static bool fill_texpaint_slots_cb(bNode *node, void *userdata)
ma->paint_active_slot = index;
}
- ma->texpaintslot[index].ima = (Image *)node->id;
- ma->texpaintslot[index].interp = ((NodeTexImage *)node->storage)->interpolation;
+ switch (node->type) {
+ case SH_NODE_TEX_IMAGE: {
+ TexPaintSlot *slot = &ma->texpaintslot[index];
+ slot->ima = (Image *)node->id;
+ slot->interp = ((NodeTexImage *)node->storage)->interpolation;
+ /* for new renderer, we need to traverse the treeback in search of a UV node */
+ bNode *uvnode = nodetree_uv_node_recursive(node);
- /* for new renderer, we need to traverse the treeback in search of a UV node */
- bNode *uvnode = nodetree_uv_node_recursive(node);
+ if (uvnode) {
+ NodeShaderUVMap *storage = (NodeShaderUVMap *)uvnode->storage;
+ slot->uvname = storage->uv_map;
+ /* set a value to index so UI knows that we have a valid pointer for the mesh */
+ slot->valid = true;
+ }
+ else {
+ /* just invalidate the index here so UV map does not get displayed on the UI */
+ slot->valid = false;
+ }
+ break;
+ }
- if (uvnode) {
- NodeShaderUVMap *storage = (NodeShaderUVMap *)uvnode->storage;
- ma->texpaintslot[index].uvname = storage->uv_map;
- /* set a value to index so UI knows that we have a valid pointer for the mesh */
- ma->texpaintslot[index].valid = true;
- }
- else {
- /* just invalidate the index here so UV map does not get displayed on the UI */
- ma->texpaintslot[index].valid = false;
+ case SH_NODE_ATTRIBUTE: {
+ TexPaintSlot *slot = &ma->texpaintslot[index];
+ NodeShaderAttribute *storage = node->storage;
+ slot->attribute_name = storage->name;
+ if (storage->type == SHD_ATTRIBUTE_GEOMETRY) {
+ const Mesh *mesh = (const Mesh *)fill_data->ob->data;
+ CustomDataLayer *layer = BKE_id_attributes_color_find(&mesh->id, storage->name);
+ slot->valid = layer != NULL;
+ }
+
+ /* Do not show unsupported attributes. */
+ if (!slot->valid) {
+ slot->attribute_name = NULL;
+ fill_data->index--;
+ }
+
+ break;
+ }
}
return fill_data->index != fill_data->slot_len;
@@ -1424,14 +1465,26 @@ static bool fill_texpaint_slots_cb(bNode *node, void *userdata)
static void fill_texpaint_slots_recursive(bNodeTree *nodetree,
bNode *active_node,
+ const Object *ob,
Material *ma,
- int slot_len)
+ int slot_len,
+ ePaintSlotFilter slot_filter)
+{
+ struct FillTexPaintSlotsData fill_data = {active_node, ob, ma, 0, slot_len};
+ ntree_foreach_texnode_recursive(nodetree, fill_texpaint_slots_cb, &fill_data, slot_filter);
+}
+
+/** Check which type of paint slots should be filled for the given object. */
+static ePaintSlotFilter material_paint_slot_filter(const struct Object *ob)
{
- struct FillTexPaintSlotsData fill_data = {active_node, ma, 0, slot_len};
- ntree_foreach_texnode_recursive(nodetree, fill_texpaint_slots_cb, &fill_data);
+ ePaintSlotFilter slot_filter = PAINT_SLOT_IMAGE;
+ if (ob->mode == OB_MODE_SCULPT && U.experimental.use_sculpt_texture_paint) {
+ slot_filter |= PAINT_SLOT_COLOR_ATTRIBUTE;
+ }
+ return slot_filter;
}
-void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma)
+void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma, const struct Object *ob)
{
int count = 0;
@@ -1439,6 +1492,8 @@ void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma)
return;
}
+ const ePaintSlotFilter slot_filter = material_paint_slot_filter(ob);
+
/* COW needed when adding texture slot on an object with no materials. */
DEG_id_tag_update(&ma->id, ID_RECALC_SHADING | ID_RECALC_COPY_ON_WRITE);
@@ -1460,7 +1515,7 @@ void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma)
return;
}
- count = count_texture_nodes_recursive(ma->nodetree);
+ count = count_texture_nodes_recursive(ma->nodetree, slot_filter);
if (count == 0) {
ma->paint_active_slot = 0;
@@ -1470,9 +1525,9 @@ void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma)
ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots");
- bNode *active_node = nodeGetActiveTexture(ma->nodetree);
+ bNode *active_node = nodeGetActivePaintCanvas(ma->nodetree);
- fill_texpaint_slots_recursive(ma->nodetree, active_node, ma, count);
+ fill_texpaint_slots_recursive(ma->nodetree, active_node, ob, ma, count, slot_filter);
ma->tot_slots = count;
@@ -1489,22 +1544,32 @@ void BKE_texpaint_slots_refresh_object(Scene *scene, struct Object *ob)
{
for (int i = 1; i < ob->totcol + 1; i++) {
Material *ma = BKE_object_material_get(ob, i);
- BKE_texpaint_slot_refresh_cache(scene, ma);
+ BKE_texpaint_slot_refresh_cache(scene, ma, ob);
}
}
struct FindTexPaintNodeData {
- Image *ima;
+ TexPaintSlot *slot;
bNode *r_node;
};
static bool texpaint_slot_node_find_cb(bNode *node, void *userdata)
{
struct FindTexPaintNodeData *find_data = userdata;
- Image *ima = (Image *)node->id;
- if (find_data->ima == ima) {
- find_data->r_node = node;
- return false;
+ if (find_data->slot->ima && node->type == SH_NODE_TEX_IMAGE) {
+ Image *node_ima = (Image *)node->id;
+ if (find_data->slot->ima == node_ima) {
+ find_data->r_node = node;
+ return false;
+ }
+ }
+
+ if (find_data->slot->attribute_name && node->type == SH_NODE_ATTRIBUTE) {
+ NodeShaderAttribute *storage = node->storage;
+ if (STREQLEN(find_data->slot->attribute_name, storage->name, sizeof(storage->name))) {
+ find_data->r_node = node;
+ return false;
+ }
}
return true;
@@ -1512,8 +1577,12 @@ static bool texpaint_slot_node_find_cb(bNode *node, void *userdata)
bNode *BKE_texpaint_slot_material_find_node(Material *ma, short texpaint_slot)
{
- struct FindTexPaintNodeData find_data = {ma->texpaintslot[texpaint_slot].ima, NULL};
- ntree_foreach_texnode_recursive(ma->nodetree, texpaint_slot_node_find_cb, &find_data);
+ TexPaintSlot *slot = &ma->texpaintslot[texpaint_slot];
+ struct FindTexPaintNodeData find_data = {slot, NULL};
+ ntree_foreach_texnode_recursive(ma->nodetree,
+ texpaint_slot_node_find_cb,
+ &find_data,
+ PAINT_SLOT_IMAGE | PAINT_SLOT_COLOR_ATTRIBUTE);
return find_data.r_node;
}
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 76b66beaf0d..7efdd855a04 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -3610,19 +3610,17 @@ void nodeClearActive(bNodeTree *ntree)
void nodeSetActive(bNodeTree *ntree, bNode *node)
{
- /* make sure only one node is active, and only one per ID type */
- LISTBASE_FOREACH (bNode *, tnode, &ntree->nodes) {
- tnode->flag &= ~NODE_ACTIVE;
+ const bool is_paint_canvas = nodeSupportsActiveFlag(node, NODE_ACTIVE_PAINT_CANVAS);
+ const bool is_texture_class = nodeSupportsActiveFlag(node, NODE_ACTIVE_TEXTURE);
+ int flags_to_set = NODE_ACTIVE;
+ SET_FLAG_FROM_TEST(flags_to_set, is_paint_canvas, NODE_ACTIVE_PAINT_CANVAS);
+ SET_FLAG_FROM_TEST(flags_to_set, is_texture_class, NODE_ACTIVE_TEXTURE);
- if (node->typeinfo->nclass == NODE_CLASS_TEXTURE) {
- tnode->flag &= ~NODE_ACTIVE_TEXTURE;
- }
- }
-
- node->flag |= NODE_ACTIVE;
- if (node->typeinfo->nclass == NODE_CLASS_TEXTURE) {
- node->flag |= NODE_ACTIVE_TEXTURE;
+ /* Make sure only one node is active per node tree. */
+ LISTBASE_FOREACH (bNode *, tnode, &ntree->nodes) {
+ tnode->flag &= ~flags_to_set;
}
+ node->flag |= flags_to_set;
}
int nodeSocketIsHidden(const bNodeSocket *sock)
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 8e87f6ea243..eb3f47760fc 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -42,6 +42,7 @@
#include "BKE_key.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
+#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_mesh_runtime.h"
@@ -1769,6 +1770,12 @@ static void sculpt_update_object(Depsgraph *depsgraph,
}
}
}
+
+ /* We could be more precise when we have access to the active tool. */
+ const bool use_paint_slots = (ob->mode & OB_MODE_SCULPT) != 0;
+ if (use_paint_slots) {
+ BKE_texpaint_slots_refresh_object(scene, ob);
+ }
}
void BKE_sculpt_update_object_before_eval(Object *ob)