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/intern/material.c
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/intern/material.c')
-rw-r--r--source/blender/blenkernel/intern/material.c135
1 files changed, 102 insertions, 33 deletions
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;
}