Compare commits

...

55 Commits

Author SHA1 Message Date
d466b0378a Revert removal of force shading color to vertex colors. 2022-04-08 08:21:25 +02:00
c71027705c Show Canvas selector only when experimental flag is enabled. 2022-04-08 08:15:02 +02:00
15aea1bb22 Merge remote-tracking branch 'origin/master' into temp-T96709-painting-target 2022-04-08 07:59:39 +02:00
d6a741ae83 Remove 'sculpt vertex mode' shading mode switch. 2022-04-06 10:50:15 +02:00
da172ea0f6 Add attribute selection using material source. 2022-04-06 10:43:17 +02:00
8648d7145f Only show material attributes that are supported. 2022-04-06 10:27:20 +02:00
9fe81c4719 Add specific UIList for color attribute selection. 2022-04-06 09:31:08 +02:00
ece878018f Merge remote-tracking branch 'origin/master' into temp-T96709-painting-target 2022-04-06 09:04:32 +02:00
b7c46bb7fa Remove unused code. 2022-04-06 08:20:05 +02:00
26910f68ad Fix memory leak. 2022-04-05 15:25:41 +02:00
2878a75e82 Change RNA API. 2022-04-05 15:20:30 +02:00
3e095d3495 Use MAX_NAME. 2022-04-05 13:52:43 +02:00
66a3a589fa Don't trigger depsgraph update when switching tools. 2022-04-05 13:50:06 +02:00
a327d98d3c WIP. switching machines for proper GPU debugging session.
Workbench draws in material mode, but screen is still showing vertex mode.
2022-04-05 11:32:24 +02:00
82863e94c9 Replace depsgraph update with pbvh node tagging. 2022-04-05 10:51:21 +02:00
b9c48323b6 Remove commented out code in workbench. 2022-04-05 10:24:16 +02:00
7bf8459c13 Added sticky_shading_color (temporarily until paint mode has been added). 2022-04-05 10:22:03 +02:00
ce0a5a435e Don't use override as variable name. 2022-04-05 08:19:53 +02:00
f71609fe59 Merge remote-tracking branch 'origin/master' into temp-T96709-painting-target 2022-04-05 08:14:29 +02:00
8323541a05 Merge branch 'master' into temp-T96709-painting-target 2022-04-04 14:19:32 +02:00
5c22f28334 Fix refreshing after load. 2022-03-30 11:16:46 +02:00
3b4031718a Update paint slots when object changes. 2022-03-30 09:13:18 +02:00
821d389da4 TexPaintSlot comments. 2022-03-30 08:19:25 +02:00
5e2bb3eed2 Comments. 2022-03-30 08:17:34 +02:00
c25d986111 Remove unneeded forward declaration. 2022-03-30 08:13:46 +02:00
f4792e6801 Rename to ED_paint_shading_color_override. 2022-03-30 08:12:54 +02:00
9644f3acfb Small changes to BKE_material API. 2022-03-30 08:11:25 +02:00
6231a4ce24 Merge remote-tracking branch 'origin/master' into temp-T96709-painting-target 2022-03-30 08:07:21 +02:00
17125fb75d Show icon of tex paint slot. 2022-03-29 17:13:06 +02:00
40e27448b3 Rename helper class. 2022-03-29 16:02:36 +02:00
9a6dcc340b Use flag to update paint slots. 2022-03-29 15:55:06 +02:00
c5de824d82 Remove unused include. 2022-03-29 15:21:55 +02:00
a92219b2f3 Updated comments. 2022-03-29 15:21:15 +02:00
79a7d38c4c Cleaup include statements. 2022-03-29 15:19:31 +02:00
8ba7440aec Revert indentation. 2022-03-29 15:16:29 +02:00
6f0dfb2448 Fixed update issues using texpaintslot selection. 2022-03-29 15:01:40 +02:00
5a33f6be4f Moving towards TexPaintSlot. 2022-03-29 13:54:47 +02:00
a87f9f8081 Connect python panel to use ED_paint_tool_use_canvas logic. 2022-03-29 10:53:18 +02:00
2fff10e2bf Use wmMsgBus to notify active tool changes. 2022-03-29 09:25:40 +02:00
a38d07223e Toolsystem uses paint canvas. 2022-03-28 15:26:14 +02:00
3bd3bc7122 Switching canvas sources. 2022-03-28 13:50:41 +02:00
36e6b4d32a Revert code style change. 2022-03-28 12:15:31 +02:00
cc8dfac9a9 Remove unneeded comment. 2022-03-28 12:15:22 +02:00
5ef083cd3a Code formatting. 2022-03-28 12:13:34 +02:00
69ead4b848 Renamed enum values (added SOURCE_). 2022-03-28 12:12:58 +02:00
22ea079310 Wrap material resource index. 2022-03-28 12:04:38 +02:00
42c5fd505e Change shading coloring in workbench based on active node. 2022-03-28 11:46:16 +02:00
0fc46d05e5 Only show images when texture painting feature is enabled. 2022-03-28 09:45:42 +02:00
6a8bd6e598 Color attribute switching. 2022-03-25 15:25:26 +01:00
a8993dd12a Show all paint resources of material slots. 2022-03-25 12:21:09 +01:00
66d0b1b5c3 Update poll function. 2022-03-23 16:39:57 +01:00
08297586ed Small changes to UI. 2022-03-23 16:03:46 +01:00
b8d7bbd15b Initial UI. 2022-03-23 14:06:04 +01:00
1ae8622d47 Add initial RNA/DNA struct. 2022-03-23 12:12:53 +01:00
fb76179758 Add experimental feature for 3d texture painting. 2022-03-23 11:17:58 +01:00
28 changed files with 783 additions and 125 deletions

View File

@@ -565,7 +565,7 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel):
layout.label(text="Name collisions: " + ", ".join(set(colliding_names)), icon='ERROR')
class MESH_UL_color_attributes(UIList):
class ColorAttributesListBase():
display_domain_names = {
'POINT': "Vertex",
'EDGE': "Edge",
@@ -588,6 +588,8 @@ class MESH_UL_color_attributes(UIList):
return ret, idxs
class MESH_UL_color_attributes(UIList, ColorAttributesListBase):
def draw_item(self, _context, layout, data, attribute, _icon, _active_data, _active_propname, _index):
data_type = attribute.bl_rna.properties['data_type'].enum_items[attribute.data_type]
@@ -613,6 +615,12 @@ class MESH_UL_color_attributes(UIList):
sub.label(text="%s%s" % (domain_name, data_type.name))
class MESH_UL_color_attributes_selector(UIList, ColorAttributesListBase):
def draw_item(self, _context, layout, data, attribute, _icon, _active_data, _active_propname, _index):
layout.emboss = 'NONE'
layout.prop(attribute, "name", text="", icon='COLOR')
class DATA_PT_vertex_colors(DATA_PT_mesh_attributes, Panel):
bl_label = "Color Attributes"
bl_options = {'DEFAULT_CLOSED'}
@@ -663,6 +671,7 @@ classes = (
DATA_PT_customdata,
DATA_PT_custom_props_mesh,
MESH_UL_color_attributes,
MESH_UL_color_attributes_selector,
)
if __name__ == "__main__": # only for live edit.

View File

@@ -238,7 +238,7 @@ class ClonePanel(BrushPanel):
col.label(text="Source Clone Slot")
col.template_list(
"TEXTURE_UL_texpaintslots", "",
mat, "texture_paint_images",
mat, "texture_paint_slots",
mat, "paint_clone_slot",
rows=2,
)

View File

@@ -280,7 +280,7 @@ class TEXTURE_UL_texpaintslots(UIList):
# mat = data
if self.layout_type in {'DEFAULT', 'COMPACT'}:
layout.prop(item, "name", text="", emboss=False, icon_value=icon)
layout.prop(item, "name", text="", emboss=False, icon_value=item.icon_value)
elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="")
@@ -459,15 +459,11 @@ class VIEW3D_MT_tools_projectpaint_uvlayer(Menu):
props.value = i
class VIEW3D_PT_slots_projectpaint(View3DPanel, Panel):
class SelectPaintSlotHelper:
bl_category = "Tool"
bl_context = ".imagepaint" # dot on purpose (access from topbar)
bl_label = "Texture Slots"
@classmethod
def poll(cls, context):
brush = context.tool_settings.image_paint.brush
return (brush is not None and context.active_object is not None)
canvas_source_attr_name = "canvas_source"
canvas_image_attr_name = "canvas_image"
def draw(self, context):
layout = self.layout
@@ -475,51 +471,66 @@ class VIEW3D_PT_slots_projectpaint(View3DPanel, Panel):
layout.use_property_decorate = False
settings = context.tool_settings.image_paint
mode_settings = self.get_mode_settings(context)
ob = context.active_object
layout.prop(settings, "mode", text="Mode")
layout.prop(mode_settings, self.canvas_source_attr_name, text="Mode")
layout.separator()
if settings.mode == 'MATERIAL':
if len(ob.material_slots) > 1:
layout.template_list("MATERIAL_UL_matslots", "layers",
ob, "material_slots",
ob, "active_material_index", rows=2)
mat = ob.active_material
if mat and mat.texture_paint_images:
row = layout.row()
row.template_list("TEXTURE_UL_texpaintslots", "",
mat, "texture_paint_images",
mat, "paint_active_slot", rows=2)
have_image = False
if mat.texture_paint_slots:
slot = mat.texture_paint_slots[mat.paint_active_slot]
match getattr(mode_settings, self.canvas_source_attr_name):
case 'MATERIAL':
if len(ob.material_slots) > 1:
layout.template_list("MATERIAL_UL_matslots", "layers",
ob, "material_slots",
ob, "active_material_index", rows=2)
mat = ob.active_material
if mat and mat.texture_paint_images:
row = layout.row()
row.template_list("TEXTURE_UL_texpaintslots", "",
mat, "texture_paint_slots",
mat, "paint_active_slot", rows=2)
if mat.texture_paint_slots:
slot = mat.texture_paint_slots[mat.paint_active_slot]
else:
slot = None
have_image = slot is not None
else:
slot = None
row = layout.row()
have_image = slot is not None
else:
row = layout.row()
box = row.box()
box.label(text="No Textures")
box = row.box()
box.label(text="No Textures")
have_image = False
sub = row.column(align=True)
sub.operator_menu_enum("paint.add_texture_paint_slot", "type", icon='ADD', text="")
sub = row.column(align=True)
sub.operator_menu_enum("paint.add_texture_paint_slot", "type", icon='ADD', text="")
case 'IMAGE':
mesh = ob.data
uv_text = mesh.uv_layers.active.name if mesh.uv_layers.active else ""
layout.template_ID(mode_settings, self.canvas_image_attr_name, new="image.new", open="image.open")
if settings.missing_uvs:
layout.operator("paint.add_simple_uvs", icon='ADD', text="Add UVs")
else:
layout.menu("VIEW3D_MT_tools_projectpaint_uvlayer", text=uv_text, translate=False)
have_image = getattr(settings, self.canvas_image_attr_name) is not None
self.draw_image_interpolation(layout=layout, mode_settings=mode_settings)
elif settings.mode == 'IMAGE':
mesh = ob.data
uv_text = mesh.uv_layers.active.name if mesh.uv_layers.active else ""
layout.template_ID(settings, "canvas", new="image.new", open="image.open")
if settings.missing_uvs:
layout.operator("paint.add_simple_uvs", icon='ADD', text="Add UVs")
else:
layout.menu("VIEW3D_MT_tools_projectpaint_uvlayer", text=uv_text, translate=False)
have_image = settings.canvas is not None
layout.prop(settings, "interpolation", text="")
case 'COLOR_ATTRIBUTE':
mesh = ob.data
layout.template_list(
"MESH_UL_color_attributes_selector",
"color_attributes",
mesh,
"color_attributes",
mesh.color_attributes,
"active_color_index",
rows=3,
)
if settings.missing_uvs:
layout.separator()
@@ -531,6 +542,50 @@ class VIEW3D_PT_slots_projectpaint(View3DPanel, Panel):
layout.operator("image.save_all_modified", text="Save All Images", icon='FILE_TICK')
class VIEW3D_PT_slots_projectpaint(SelectPaintSlotHelper, View3DPanel, Panel):
bl_category = "Tool"
bl_context = ".imagepaint" # dot on purpose (access from topbar)
bl_label = "Texture Slots"
canvas_source_attr_name = "mode"
canvas_image_attr_name = "canvas"
@classmethod
def poll(cls, context):
brush = context.tool_settings.image_paint.brush
return (brush is not None and context.active_object is not None)
def get_mode_settings(self, context):
return context.tool_settings.image_paint
def draw_image_interpolation(self, layout, mode_settings):
layout.prop(mode_settings, "interpolation", text="")
class VIEW3D_PT_slots_paint_canvas(SelectPaintSlotHelper, View3DPanel, Panel):
bl_category = "Tool"
bl_context = ".sculpt_mode" # dot on purpose (access from topbar)
bl_label = "Canvas"
@classmethod
def poll(cls, context):
if not context.preferences.experimental.use_sculpt_texture_paint:
return False
from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
tool = ToolSelectPanelHelper.tool_active_from_context(context)
if tool is None:
return False
return tool.use_paint_canvas
def get_mode_settings(self, context):
return context.tool_settings.paint_mode
def draw_image_interpolation(self, **kwargs):
pass
class VIEW3D_PT_mask(View3DPanel, Panel):
bl_category = "Tool"
bl_context = ".imagepaint" # dot on purpose (access from topbar)
@@ -2232,6 +2287,7 @@ classes = (
VIEW3D_PT_tools_posemode_options,
VIEW3D_PT_slots_projectpaint,
VIEW3D_PT_slots_paint_canvas,
VIEW3D_PT_tools_brush_select,
VIEW3D_PT_tools_brush_settings,
VIEW3D_PT_tools_brush_color,

View File

@@ -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);

View File

@@ -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);

View File

@@ -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,

View File

@@ -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);

View File

@@ -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,

View File

@@ -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, ma, 0, slot_len};
ntree_foreach_texnode_recursive(nodetree, fill_texpaint_slots_cb, &fill_data);
struct FillTexPaintSlotsData fill_data = {active_node, ob, ma, 0, slot_len};
ntree_foreach_texnode_recursive(nodetree, fill_texpaint_slots_cb, &fill_data, slot_filter);
}
void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma)
/** Check which type of paint slots should be filled for the given object. */
static ePaintSlotFilter material_paint_slot_filter(const struct Object *ob)
{
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, 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;
}

View File

@@ -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 */
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);
/* Make sure only one node is active per node tree. */
LISTBASE_FOREACH (bNode *, tnode, &ntree->nodes) {
tnode->flag &= ~NODE_ACTIVE;
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;
tnode->flag &= ~flags_to_set;
}
node->flag |= flags_to_set;
}
int nodeSocketIsHidden(const bNodeSocket *sock)

View File

@@ -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)

View File

@@ -27,6 +27,8 @@
#include "DNA_modifier_types.h"
#include "DNA_node_types.h"
#include "ED_paint.h"
#include "workbench_engine.h"
#include "workbench_private.h"
@@ -94,8 +96,6 @@ static void workbench_cache_sculpt_populate(WORKBENCH_PrivateData *wpd,
eV3DShadingColorType color_type)
{
const bool use_single_drawcall = !ELEM(color_type, V3D_SHADING_MATERIAL_COLOR);
BLI_assert(color_type != V3D_SHADING_TEXTURE_COLOR);
if (use_single_drawcall) {
DRWShadingGroup *grp = workbench_material_setup(wpd, ob, 0, color_type, NULL);
DRW_shgroup_call_sculpt(grp, ob, false, false);
@@ -324,6 +324,16 @@ static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd,
color_type = V3D_SHADING_MATERIAL_COLOR;
}
if (is_sculpt_pbvh) {
/* Bad call C is required to access the tool system that is context aware. Cast to non-const
* due to current API. */
bContext *C = (bContext *)DRW_context_state_get()->evil_C;
if (C != NULL) {
color_type = ED_paint_shading_color_override(
C, &wpd->scene->toolsettings->paint_mode, ob, color_type);
}
}
if (r_draw_shadow) {
*r_draw_shadow = (ob->dtx & OB_DRAW_NO_SHADOW_CAST) == 0 && SHADOW_ENABLED(wpd);
/* Currently unsupported in sculpt mode. We could revert to the slow

View File

@@ -6,10 +6,13 @@
#pragma once
#include "DNA_view3d_enums.h"
#ifdef __cplusplus
extern "C" {
#endif
struct PaintModeSettings;
struct ImBuf;
struct Image;
struct ImageUser;
@@ -109,6 +112,28 @@ void ED_paintcurve_undo_push_end(struct bContext *C);
/** Export for ED_undo_sys. */
void ED_paintcurve_undosys_type(struct UndoType *ut);
/* paint_canvas.cc */
struct Image *ED_paint_canvas_image_get(const struct PaintModeSettings *settings,
struct Object *ob);
int ED_paint_canvas_uvmap_layer_index_get(const struct PaintModeSettings *settings,
struct Object *ob);
/** Color type of an object can be overridden in sculpt/paint mode. */
eV3DShadingColorType ED_paint_shading_color_override(struct bContext *C,
const struct PaintModeSettings *settings,
struct Object *ob,
eV3DShadingColorType orig_color_type);
/**
* Does the given tool use a paint canvas.
*
* When #tref isn't given the active tool from the context is used.
*/
bool ED_paint_tool_use_canvas(struct bContext *C, struct bToolRef *tref);
/* Store the last used tool in the sculpt session. */
void ED_paint_tool_update_sticky_shading_color(struct bContext *C, struct Object *ob);
#ifdef __cplusplus
}
#endif

View File

@@ -34,6 +34,7 @@ set(SRC
curves_sculpt_grow_shrink.cc
curves_sculpt_ops.cc
curves_sculpt_snake_hook.cc
paint_canvas.cc
paint_cursor.c
paint_curve.c
paint_curve_undo.c

View File

@@ -0,0 +1,203 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_compiler_compat.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_node_types.h"
#include "DNA_screen_types.h"
#include "DNA_workspace_types.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_material.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
#include "DEG_depsgraph.h"
#include "NOD_shader.h"
#include "WM_toolsystem.h"
namespace blender::ed::sculpt_paint::canvas {
static TexPaintSlot *get_active_slot(Object *ob)
{
Material *mat = BKE_object_material_get(ob, ob->actcol);
if (mat == nullptr) {
return nullptr;
}
if (mat->texpaintslot == nullptr) {
return nullptr;
}
if (mat->paint_active_slot >= mat->tot_slots) {
return nullptr;
}
TexPaintSlot *slot = &mat->texpaintslot[mat->paint_active_slot];
return slot;
}
} // namespace blender::ed::sculpt_paint::canvas
extern "C" {
using namespace blender;
using namespace blender::ed::sculpt_paint::canvas;
/* Does the paint tool with the given idname uses a canvas. */
static bool paint_tool_uses_canvas(StringRef idname)
{
return ELEM(idname, "builtin_brush.Paint", "builtin_brush.Smear", "builtin.color_filter");
}
static bool paint_tool_shading_color_follows_last_used(StringRef idname)
{
/* TODO(jbakker): complete this list. */
return ELEM(idname, "builtin_brush.Mask");
}
void ED_paint_tool_update_sticky_shading_color(struct bContext *C, struct Object *ob)
{
if (ob == nullptr || ob->sculpt == nullptr) {
return;
}
bToolRef *tref = WM_toolsystem_ref_from_context(C);
if (tref == nullptr) {
return;
}
/* Do not modify when tool follows lat used tool. */
if (paint_tool_shading_color_follows_last_used(tref->idname)) {
return;
}
ob->sculpt->sticky_shading_color = paint_tool_uses_canvas(tref->idname);
}
static bool paint_tool_shading_color_follows_last_used_tool(struct bContext *C, struct Object *ob)
{
if (ob == nullptr || ob->sculpt == nullptr) {
return false;
}
bToolRef *tref = WM_toolsystem_ref_from_context(C);
if (tref == nullptr) {
return false;
}
return paint_tool_shading_color_follows_last_used(tref->idname);
}
bool ED_paint_tool_use_canvas(struct bContext *C, bToolRef *tref)
{
if (tref == nullptr) {
tref = WM_toolsystem_ref_from_context(C);
}
if (tref == nullptr) {
return false;
}
return paint_tool_uses_canvas(tref->idname);
}
eV3DShadingColorType ED_paint_shading_color_override(bContext *C,
const PaintModeSettings *settings,
Object *ob,
eV3DShadingColorType orig_color_type)
{
if (!U.experimental.use_sculpt_texture_paint) {
return orig_color_type;
}
/* NOTE: This early exit is temporarily, until a paint mode has been added.
* For better integration with the vertex paint in sculpt mode we sticky
* with the last stoke when using tools like masking.
*/
if (!ED_paint_tool_use_canvas(C, nullptr) &&
!(paint_tool_shading_color_follows_last_used_tool(C, ob) &&
ob->sculpt->sticky_shading_color)) {
return orig_color_type;
}
eV3DShadingColorType color_type = orig_color_type;
switch (settings->canvas_source) {
case PAINT_CANVAS_SOURCE_COLOR_ATTRIBUTE:
color_type = V3D_SHADING_VERTEX_COLOR;
break;
case PAINT_CANVAS_SOURCE_IMAGE:
color_type = V3D_SHADING_TEXTURE_COLOR;
break;
case PAINT_CANVAS_SOURCE_MATERIAL: {
TexPaintSlot *slot = get_active_slot(ob);
if (slot == nullptr) {
break;
}
if (slot->ima) {
color_type = V3D_SHADING_TEXTURE_COLOR;
}
if (slot->attribute_name) {
color_type = V3D_SHADING_VERTEX_COLOR;
}
break;
}
}
return color_type;
}
Image *ED_paint_canvas_image_get(const struct PaintModeSettings *settings, struct Object *ob)
{
switch (settings->canvas_source) {
case PAINT_CANVAS_SOURCE_COLOR_ATTRIBUTE:
return nullptr;
case PAINT_CANVAS_SOURCE_IMAGE:
return settings->canvas_image;
case PAINT_CANVAS_SOURCE_MATERIAL: {
TexPaintSlot *slot = get_active_slot(ob);
if (slot == nullptr) {
break;
}
return slot->ima;
}
}
return nullptr;
}
int ED_paint_canvas_uvmap_layer_index_get(const struct PaintModeSettings *settings,
struct Object *ob)
{
switch (settings->canvas_source) {
case PAINT_CANVAS_SOURCE_COLOR_ATTRIBUTE:
return -1;
case PAINT_CANVAS_SOURCE_IMAGE: {
/* Use active uv map of the object. */
if (ob->type != OB_MESH) {
return -1;
}
const Mesh *mesh = static_cast<Mesh *>(ob->data);
return CustomData_get_active_layer_index(&mesh->ldata, CD_MLOOPUV);
}
case PAINT_CANVAS_SOURCE_MATERIAL: {
/* Use uv map of the canvas. */
TexPaintSlot *slot = get_active_slot(ob);
if (slot == nullptr) {
break;
}
if (ob->type != OB_MESH) {
return -1;
}
if (slot->uvname == nullptr) {
return -1;
}
const Mesh *mesh = static_cast<Mesh *>(ob->data);
return CustomData_get_named_layer_index(&mesh->ldata, CD_MLOOPUV, slot->uvname);
}
}
return -1;
}
}

View File

@@ -6336,7 +6336,7 @@ bool ED_paint_proj_mesh_data_check(
hasmat = true;
if (ma->texpaintslot == NULL) {
/* refresh here just in case */
BKE_texpaint_slot_refresh_cache(scene, ma);
BKE_texpaint_slot_refresh_cache(scene, ma, ob);
}
if (ma->texpaintslot != NULL &&
(ma->texpaintslot[ma->paint_active_slot].ima == NULL ||
@@ -6607,7 +6607,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
nodePositionPropagate(out_node);
if (ima) {
BKE_texpaint_slot_refresh_cache(scene, ma);
BKE_texpaint_slot_refresh_cache(scene, ma, ob);
BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_USER_NEW_IMAGE);
WM_event_add_notifier(C, NC_IMAGE | NA_ADDED, ima);
}

View File

@@ -281,7 +281,7 @@ static void imapaint_pick_uv(
float p[2], w[3], absw, minabsw;
float matrix[4][4], proj[4][4];
int view[4];
const eImagePaintMode mode = scene->toolsettings->imapaint.mode;
const ePaintCanvasSource mode = scene->toolsettings->imapaint.mode;
const MLoopTri *lt = BKE_mesh_runtime_looptri_ensure(me_eval);
const int tottri = me_eval->runtime.looptris.len;
@@ -317,7 +317,7 @@ static void imapaint_pick_uv(
copy_v3_v3(tri_co[j], mvert[mloop[lt->tri[j]].v].co);
}
if (mode == IMAGEPAINT_MODE_MATERIAL) {
if (mode == PAINT_CANVAS_SOURCE_MATERIAL) {
const Material *ma;
const TexPaintSlot *slot;
@@ -431,7 +431,7 @@ void paint_sample_color(
Material *ma = BKE_object_material_get(ob_eval, mp->mat_nr + 1);
/* Force refresh since paint slots are not updated when changing interpolation. */
BKE_texpaint_slot_refresh_cache(scene, ma);
BKE_texpaint_slot_refresh_cache(scene, ma, ob);
if (ma && ma->texpaintslot) {
image = ma->texpaintslot[ma->paint_active_slot].ima;

View File

@@ -70,6 +70,7 @@
#include "WM_types.h"
#include "ED_object.h"
#include "ED_paint.h"
#include "ED_screen.h"
#include "ED_sculpt.h"
#include "ED_view3d.h"
@@ -4991,6 +4992,8 @@ static void sculpt_brush_stroke_init(bContext *C, wmOperator *op)
* earlier steps modifying the data. */
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
BKE_sculpt_update_object_for_edit(depsgraph, ob, need_pmap, need_mask, needs_colors);
ED_paint_tool_update_sticky_shading_color(C, ob);
}
static void sculpt_restore_mesh(Sculpt *sd, Object *ob)
@@ -5191,6 +5194,8 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const f
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
/* NOTE: This should be removed when paint mode is available. Paint mode can force based on the
* canvas it is painting on. (ref. use_sculpt_texture_paint). */
if (brush && SCULPT_TOOL_NEEDS_COLOR(brush->sculpt_tool)) {
View3D *v3d = CTX_wm_view3d(C);
if (v3d) {

View File

@@ -36,6 +36,7 @@
#include "WM_types.h"
#include "ED_object.h"
#include "ED_paint.h"
#include "ED_screen.h"
#include "ED_sculpt.h"
#include "paint_intern.h"
@@ -293,6 +294,7 @@ static int sculpt_color_filter_invoke(bContext *C, wmOperator *op, const wmEvent
FilterCache *filter_cache = ss->filter_cache;
filter_cache->active_face_set = SCULPT_FACE_SET_NONE;
filter_cache->automasking = SCULPT_automasking_cache_init(sd, NULL, ob);
ED_paint_tool_update_sticky_shading_color(C, ob);
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;

View File

@@ -1300,6 +1300,27 @@ static void view3d_main_region_listener(const wmRegionListenerParams *params)
}
}
static void view3d_do_msg_notify_workbench_view_update(struct bContext *C,
struct wmMsgSubscribeKey *UNUSED(msg_key),
struct wmMsgSubscribeValue *msg_val)
{
Scene *scene = CTX_data_scene(C);
ScrArea *area = (ScrArea *)msg_val->user_data;
View3D *v3d = (View3D *)area->spacedata.first;
if (v3d->shading.type == OB_SOLID) {
RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type);
DRWUpdateContext drw_context = {NULL};
drw_context.bmain = CTX_data_main(C);
drw_context.depsgraph = CTX_data_depsgraph_pointer(C);
drw_context.scene = scene;
drw_context.view_layer = CTX_data_view_layer(C);
drw_context.region = (ARegion *)(msg_val->owner);
drw_context.v3d = v3d;
drw_context.engine_type = engine_type;
DRW_notify_view_update(&drw_context);
}
}
static void view3d_main_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
{
struct wmMsgBus *mbus = params->message_bus;
@@ -1341,6 +1362,12 @@ static void view3d_main_region_message_subscribe(const wmRegionMessageSubscribeP
.notify = ED_region_do_msg_notify_tag_redraw,
};
wmMsgSubscribeValue msg_sub_value_workbench_view_update = {
.owner = region,
.user_data = area,
.notify = view3d_do_msg_notify_workbench_view_update,
};
for (int i = 0; i < ARRAY_SIZE(type_array); i++) {
msg_key_params.ptr.type = type_array[i];
WM_msg_subscribe_rna_params(mbus, &msg_key_params, &msg_sub_value_region_tag_redraw, __func__);
@@ -1374,6 +1401,11 @@ static void view3d_main_region_message_subscribe(const wmRegionMessageSubscribeP
case OB_MODE_PARTICLE_EDIT:
WM_msg_subscribe_rna_anon_type(mbus, ParticleEdit, &msg_sub_value_region_tag_redraw);
break;
case OB_MODE_SCULPT:
WM_msg_subscribe_rna_anon_prop(
mbus, WorkSpace, tools, &msg_sub_value_workbench_view_update);
break;
default:
break;
}

View File

@@ -27,11 +27,16 @@ struct bNodeTree;
/* WATCH IT: change type? also make changes in ipo.h */
typedef struct TexPaintSlot {
/** Image to be painted on. */
/** Image to be painted on. Mutual exclusive with attribute_name. */
struct Image *ima;
/** Custom-data index for uv layer, #MAX_NAME. */
char *uvname;
/** Do we have a valid image and UV map. */
/**
* Color attribute name when painting using color attributes. Mutual exclusive with ima.
* Points to the name of a CustomDataLayer.
*/
char *attribute_name;
/** Do we have a valid image and UV map or attribute. */
int valid;
/** Copy of node interpolation setting. */
int interp;

View File

@@ -397,6 +397,8 @@ typedef struct bNode {
#define NODE_DO_OUTPUT_RECALC (1 << 17)
/* A preview for the data in this node can be displayed in the spreadsheet editor. */
#define __NODE_ACTIVE_PREVIEW (1 << 18) /* deprecated */
/* Active node that is used to paint on. */
#define NODE_ACTIVE_PAINT_CANVAS (1 << 19)
/* node->update */
#define NODE_UPDATE_ID 1 /* associated id data block has changed */

View File

@@ -929,6 +929,19 @@ typedef struct ImagePaintSettings {
char _pad[4];
} ImagePaintSettings;
/* ------------------------------------------- */
/* Paint mode settings */
typedef struct PaintModeSettings {
/** Source to select canvas from to paint on (ePaintCanvasSource) */
char canvas_source;
char _pad[7];
/** Selected image when canvas_source=PAINT_CANVAS_SOURCE_IMAGE. */
Image *canvas_image;
} PaintModeSettings;
/* ------------------------------------------- */
/* Particle Edit */
@@ -1462,6 +1475,9 @@ typedef struct ToolSettings {
/* Image Paint (8 bytes aligned please!) */
struct ImagePaintSettings imapaint;
/** Settings for paint mode. */
struct PaintModeSettings paint_mode;
/* Particle Editing */
struct ParticleEditSettings particle;
@@ -2278,11 +2294,21 @@ typedef enum eSculptFlags {
SCULPT_HIDE_FACE_SETS = (1 << 17),
} eSculptFlags;
/** PaintModeSettings.mode */
typedef enum ePaintCanvasSource {
/** Paint on the active node of the active material slot. */
PAINT_CANVAS_SOURCE_MATERIAL = 0,
/** Paint on a selected image. */
PAINT_CANVAS_SOURCE_IMAGE = 1,
/** Paint on the active color attribute (vertex color) layer. */
PAINT_CANVAS_SOURCE_COLOR_ATTRIBUTE = 2,
} ePaintCanvasSource;
/** #ImagePaintSettings.mode */
typedef enum eImagePaintMode {
IMAGEPAINT_MODE_MATERIAL = 0, /* detect texture paint slots from the material */
IMAGEPAINT_MODE_IMAGE = 1, /* select texture paint image directly */
} eImagePaintMode;
/* Defines to let old texture painting use the new enum. */
/* TODO(jbakker): rename usages. */
#define IMAGEPAINT_MODE_MATERIAL PAINT_CANVAS_SOURCE_MATERIAL
#define IMAGEPAINT_MODE_IMAGE PAINT_CANVAS_SOURCE_IMAGE
/** #ImagePaintSettings.interp */
enum {

View File

@@ -8,10 +8,13 @@
#include <stdlib.h>
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_texture_types.h"
#include "BLI_math.h"
#include "BKE_customdata.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -136,10 +139,9 @@ static void rna_Material_texpaint_begin(CollectionPropertyIterator *iter, Pointe
iter, (void *)ma->texpaintslot, sizeof(TexPaintSlot), ma->tot_slots, 0, NULL);
}
static void rna_Material_active_paint_texture_index_update(Main *bmain,
Scene *UNUSED(scene),
PointerRNA *ptr)
static void rna_Material_active_paint_texture_index_update(bContext *C, PointerRNA *ptr)
{
Main *bmain = CTX_data_main(C);
bScreen *screen;
Material *ma = (Material *)ptr->owner_id;
@@ -152,26 +154,43 @@ static void rna_Material_active_paint_texture_index_update(Main *bmain,
}
if (ma->texpaintslot) {
Image *image = ma->texpaintslot[ma->paint_active_slot].ima;
for (screen = bmain->screens.first; screen; screen = screen->id.next) {
wmWindow *win = ED_screen_window_find(screen, bmain->wm.first);
if (win == NULL) {
continue;
}
TexPaintSlot *slot = &ma->texpaintslot[ma->paint_active_slot];
Image *image = slot->ima;
if (image) {
for (screen = bmain->screens.first; screen; screen = screen->id.next) {
wmWindow *win = ED_screen_window_find(screen, bmain->wm.first);
if (win == NULL) {
continue;
}
ScrArea *area;
for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_IMAGE) {
SpaceImage *sima = (SpaceImage *)sl;
if (!sima->pin) {
ED_space_image_set(bmain, sima, image, true);
ScrArea *area;
for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_IMAGE) {
SpaceImage *sima = (SpaceImage *)sl;
if (!sima->pin) {
ED_space_image_set(bmain, sima, image, true);
}
}
}
}
}
}
/* For compatibility reasons with vertex paint we activate the color attribute. */
if (slot->attribute_name) {
Object *ob = CTX_data_active_object(C);
if (ob != NULL && ob->type == OB_MESH) {
Mesh *mesh = ob->data;
CustomDataLayer *layer = BKE_id_attributes_color_find(&mesh->id, slot->attribute_name);
if (layer != NULL) {
BKE_id_attributes_active_color_set(&mesh->id, layer);
}
DEG_id_tag_update(&ob->id, 0);
WM_main_add_notifier(NC_GEOM | ND_DATA, &ob->id);
}
}
}
DEG_id_tag_update(&ma->id, 0);
@@ -281,6 +300,49 @@ static void rna_TexPaintSlot_uv_layer_set(PointerRNA *ptr, const char *value)
}
}
static void rna_TexPaintSlot_name_get(PointerRNA *ptr, char *value)
{
TexPaintSlot *data = (TexPaintSlot *)(ptr->data);
if (data->ima != NULL) {
BLI_strncpy_utf8(value, data->ima->id.name + 2, MAX_NAME);
return;
}
if (data->attribute_name != NULL) {
BLI_strncpy_utf8(value, data->attribute_name, MAX_NAME);
return;
}
value[0] = '\0';
}
static int rna_TexPaintSlot_name_length(PointerRNA *ptr)
{
TexPaintSlot *data = (TexPaintSlot *)(ptr->data);
if (data->ima != NULL) {
return strlen(data->ima->id.name) - 2;
}
if (data->attribute_name != NULL) {
return strlen(data->attribute_name);
}
return 0;
}
static int rna_TexPaintSlot_icon_get(PointerRNA *ptr)
{
TexPaintSlot *data = (TexPaintSlot *)(ptr->data);
if (data->ima != NULL) {
return ICON_IMAGE;
}
if (data->attribute_name != NULL) {
return ICON_COLOR;
}
return ICON_NONE;
}
static bool rna_is_grease_pencil_get(PointerRNA *ptr)
{
Material *ma = (Material *)ptr->data;
@@ -963,6 +1025,17 @@ static void rna_def_tex_slot(BlenderRNA *brna)
RNA_def_struct_ui_text(
srna, "Texture Paint Slot", "Slot that contains information about texture painting");
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_string_funcs(
prop, "rna_TexPaintSlot_name_get", "rna_TexPaintSlot_name_length", NULL);
RNA_def_property_ui_text(prop, "Name", "Name of the slot");
prop = RNA_def_property(srna, "icon_value", PROP_INT, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_int_funcs(prop, "rna_TexPaintSlot_icon_get", NULL, NULL);
RNA_def_property_ui_text(prop, "Icon", "Paint slot icon");
prop = RNA_def_property(srna, "uv_layer", PROP_STRING, PROP_NONE);
RNA_def_property_string_maxlength(prop, 64); /* else it uses the pointer size! */
RNA_def_property_string_sdna(prop, NULL, "uvname");
@@ -1019,6 +1092,7 @@ void rna_def_texpaint_slots(BlenderRNA *brna, StructRNA *srna)
RNA_def_property_range(prop, 0, SHRT_MAX);
RNA_def_property_ui_text(
prop, "Active Paint Texture Index", "Index of active texture paint slot");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(
prop, NC_MATERIAL | ND_SHADING_LINKS, "rna_Material_active_paint_texture_index_update");

View File

@@ -3049,6 +3049,10 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "imapaint");
RNA_def_property_ui_text(prop, "Image Paint", "");
prop = RNA_def_property(srna, "paint_mode", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "paint_mode");
RNA_def_property_ui_text(prop, "Paint Mode", "");
prop = RNA_def_property(srna, "uv_sculpt", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "uvsculpt");
RNA_def_property_ui_text(prop, "UV Sculpt", "");

View File

@@ -84,6 +84,13 @@ static const EnumPropertyItem rna_enum_gpencil_paint_mode[] = {
};
#endif
static const EnumPropertyItem rna_enum_canvas_source_items[] = {
{PAINT_CANVAS_SOURCE_COLOR_ATTRIBUTE, "COLOR_ATTRIBUTE", 0, "Color Attribute", ""},
{PAINT_CANVAS_SOURCE_MATERIAL, "MATERIAL", 0, "Material", ""},
{PAINT_CANVAS_SOURCE_IMAGE, "IMAGE", 0, "Image", ""},
{0, NULL, 0, NULL, NULL},
};
const EnumPropertyItem rna_enum_symmetrize_direction_items[] = {
{BMO_SYMMETRIZE_NEGATIVE_X, "NEGATIVE_X", 0, "-X to +X", ""},
{BMO_SYMMETRIZE_POSITIVE_X, "POSITIVE_X", 0, "+X to -X", ""},
@@ -418,6 +425,11 @@ static char *rna_ImagePaintSettings_path(PointerRNA *UNUSED(ptr))
return BLI_strdup("tool_settings.image_paint");
}
static char *rna_PaintModeSettings_path(PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.paint_mode");
}
static char *rna_UvSculpt_path(PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.uv_sculpt");
@@ -537,6 +549,30 @@ static void rna_ImaPaint_canvas_update(bContext *C, PointerRNA *UNUSED(ptr))
}
}
/** \name Paint mode settings
* \{ */
static bool rna_PaintModeSettings_canvas_image_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
{
Image *image = (Image *)value.owner_id;
return !ELEM(image->type, IMA_TYPE_COMPOSITE, IMA_TYPE_R_RESULT);
}
static void rna_PaintModeSettings_canvas_source_update(bContext *C, PointerRNA *UNUSED(ptr))
{
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
/* When canvas source changes the pbvh would require updates when switching between color
* attributes. */
if (ob && ob->type == OB_MESH) {
BKE_texpaint_slots_refresh_object(scene, ob);
DEG_id_tag_update(&ob->id, 0);
WM_main_add_notifier(NC_GEOM | ND_DATA, &ob->id);
}
}
/* \} */
static bool rna_ImaPaint_detect_data(ImagePaintSettings *imapaint)
{
return imapaint->missing_data == 0;
@@ -964,6 +1000,29 @@ static void rna_def_vertex_paint(BlenderRNA *brna)
prop, "Radial Symmetry Count X Axis", "Number of times to copy strokes across the surface");
}
static void rna_def_paint_mode(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "PaintModeSettings", NULL);
RNA_def_struct_sdna(srna, "PaintModeSettings");
RNA_def_struct_path_func(srna, "rna_PaintModeSettings_path");
RNA_def_struct_ui_text(srna, "Paint Mode", "Properties of paint mode");
prop = RNA_def_property(srna, "canvas_source", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_canvas_source_items);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_ui_text(prop, "Source", "Source to select canvas from");
RNA_def_property_update(prop, 0, "rna_PaintModeSettings_canvas_source_update");
prop = RNA_def_property(srna, "canvas_image", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_funcs(
prop, NULL, NULL, NULL, "rna_PaintModeSettings_canvas_image_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_CONTEXT_UPDATE);
RNA_def_property_ui_text(prop, "Texture", "Image used as as painting target");
}
static void rna_def_image_paint(BlenderRNA *brna)
{
StructRNA *srna;
@@ -1551,6 +1610,7 @@ void RNA_def_sculpt_paint(BlenderRNA *brna)
rna_def_gp_sculptpaint(brna);
rna_def_gp_weightpaint(brna);
rna_def_vertex_paint(brna);
rna_def_paint_mode(brna);
rna_def_image_paint(brna);
rna_def_particle_edit(brna);
rna_def_gpencil_guides(brna);

View File

@@ -32,6 +32,7 @@
# include "DNA_space_types.h"
# include "ED_asset.h"
# include "ED_paint.h"
# include "RNA_access.h"
@@ -180,6 +181,12 @@ const EnumPropertyItem *rna_WorkSpace_tools_mode_itemf(bContext *UNUSED(C),
return DummyRNA_DEFAULT_items;
}
static bool rna_WorkSpaceTool_use_paint_canvas_get(PointerRNA *ptr)
{
bToolRef *tref = ptr->data;
return ED_paint_tool_use_canvas(NULL, tref);
}
static int rna_WorkSpaceTool_index_get(PointerRNA *ptr)
{
bToolRef *tref = ptr->data;
@@ -291,6 +298,12 @@ static void rna_def_workspace_tool(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Tool Mode", "");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_paint_canvas", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Index", "");
RNA_def_property_boolean_funcs(prop, "rna_WorkSpaceTool_use_paint_canvas_get", NULL);
RNA_def_property_ui_text(prop, "Use Paint Canvas", "Does this tool use an painting canvas");
RNA_define_verify_sdna(0);
prop = RNA_def_property(srna, "has_datablock", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);

View File

@@ -162,8 +162,21 @@ static void data_from_gpu_stack_list(ListBase *sockets, bNodeStack **ns, GPUNode
}
}
bNode *nodeGetActiveTexture(bNodeTree *ntree)
bool nodeSupportsActiveFlag(const bNode *node, int sub_activity)
{
BLI_assert(ELEM(sub_activity, NODE_ACTIVE_TEXTURE, NODE_ACTIVE_PAINT_CANVAS));
switch (sub_activity) {
case NODE_ACTIVE_TEXTURE:
return node->typeinfo->nclass == NODE_CLASS_TEXTURE;
case NODE_ACTIVE_PAINT_CANVAS:
return ELEM(node->type, SH_NODE_TEX_IMAGE, SH_NODE_ATTRIBUTE);
}
return false;
}
static bNode *node_get_active(bNodeTree *ntree, int sub_activity)
{
BLI_assert(ELEM(sub_activity, NODE_ACTIVE_TEXTURE, NODE_ACTIVE_PAINT_CANVAS));
/* this is the node we texture paint and draw in textured draw */
bNode *inactivenode = nullptr, *activetexnode = nullptr, *activegroup = nullptr;
bool hasgroup = false;
@@ -173,14 +186,14 @@ bNode *nodeGetActiveTexture(bNodeTree *ntree)
}
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->flag & NODE_ACTIVE_TEXTURE) {
if (node->flag & sub_activity) {
activetexnode = node;
/* if active we can return immediately */
if (node->flag & NODE_ACTIVE) {
return node;
}
}
else if (!inactivenode && node->typeinfo->nclass == NODE_CLASS_TEXTURE) {
else if (!inactivenode && nodeSupportsActiveFlag(node, sub_activity)) {
inactivenode = node;
}
else if (node->type == NODE_GROUP) {
@@ -195,7 +208,7 @@ bNode *nodeGetActiveTexture(bNodeTree *ntree)
/* first, check active group for textures */
if (activegroup) {
bNode *tnode = nodeGetActiveTexture((bNodeTree *)activegroup->id);
bNode *tnode = node_get_active((bNodeTree *)activegroup->id, sub_activity);
/* active node takes priority, so ignore any other possible nodes here */
if (tnode) {
return tnode;
@@ -210,8 +223,8 @@ bNode *nodeGetActiveTexture(bNodeTree *ntree)
/* node active texture node in this tree, look inside groups */
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == NODE_GROUP) {
bNode *tnode = nodeGetActiveTexture((bNodeTree *)node->id);
if (tnode && ((tnode->flag & NODE_ACTIVE_TEXTURE) || !inactivenode)) {
bNode *tnode = node_get_active((bNodeTree *)node->id, sub_activity);
if (tnode && ((tnode->flag & sub_activity) || !inactivenode)) {
return tnode;
}
}
@@ -221,6 +234,16 @@ bNode *nodeGetActiveTexture(bNodeTree *ntree)
return inactivenode;
}
bNode *nodeGetActiveTexture(bNodeTree *ntree)
{
return node_get_active(ntree, NODE_ACTIVE_TEXTURE);
}
bNode *nodeGetActivePaintCanvas(bNodeTree *ntree)
{
return node_get_active(ntree, NODE_ACTIVE_PAINT_CANVAS);
}
void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, bNode *output_node)
{
bNodeExec *nodeexec;