From 55b6230464a140c62ec4cea4e11a4a05c8910d13 Mon Sep 17 00:00:00 2001 From: Robin Allen Date: Mon, 17 Aug 2009 18:37:58 +0000 Subject: [PATCH] Made texture nodes accessible in the interface. * Exposed Tex.use_nodes, Tex.nodetree, MTex.which_output in RNA * Added node controls to texture buttons (Use Nodes and Use Output) * Made new texture outputs have unique names by default, though unique names still aren't required. Note: The preview window in the texture buttons only takes which_output into account when in "material" mode, and in the material half of "both" mode; the plain texture display ignores the user's output choice. This is because ED_preview_draw draws a Tex* and not an MTex* -- still some work to do here. --- release/ui/buttons_texture.py | 194 ++++++++---------- source/blender/makesrna/intern/rna_texture.c | 77 ++++++- .../nodes/intern/TEX_nodes/TEX_output.c | 63 +++++- source/blender/nodes/intern/TEX_util.c | 15 +- 4 files changed, 232 insertions(+), 117 deletions(-) diff --git a/release/ui/buttons_texture.py b/release/ui/buttons_texture.py index 51a90b2c9ee..a1b89bec0ce 100644 --- a/release/ui/buttons_texture.py +++ b/release/ui/buttons_texture.py @@ -7,7 +7,8 @@ class TextureButtonsPanel(bpy.types.Panel): __context__ = "texture" def poll(self, context): - return (context.texture and context.texture.type != 'NONE') + tex = context.texture + return (tex and (tex.type != 'NONE' or tex.use_nodes)) class TEXTURE_PT_preview(TextureButtonsPanel): __label__ = "Preview" @@ -31,7 +32,7 @@ class TEXTURE_PT_preview(TextureButtonsPanel): layout.template_preview(tex, parent=br) else: layout.template_preview(tex) - + class TEXTURE_PT_context_texture(TextureButtonsPanel): __show_header__ = False @@ -61,25 +62,62 @@ class TEXTURE_PT_context_texture(TextureButtonsPanel): elif tex: split.template_ID(space, "pin_id") - if (not space.pin_id) and ( context.sculpt_object or \ - context.vertex_paint_object or \ - context.weight_paint_object or \ - context.texture_paint_object \ - ): + if (not space.pin_id) and ( + context.sculpt_object or + context.vertex_paint_object or + context.weight_paint_object or + context.texture_paint_object + ): split.itemR(space, "brush_texture", text="Brush", toggle=True) if tex: + layout.itemR(tex, "use_nodes") + split = layout.split(percentage=0.2) - - split.itemL(text="Type:") - split.itemR(tex, "type", text="") + + if tex.use_nodes: + slot = context.texture_slot + split.itemL(text="Output:") + split.itemR(slot, "output_node", text="") -class TEXTURE_PT_mapping(TextureButtonsPanel): + else: + split.itemL(text="Type:") + split.itemR(tex, "type", text="") + +class TEXTURE_PT_colors(TextureButtonsPanel): + __label__ = "Colors" + __default_closed__ = True + + def draw(self, context): + layout = self.layout + + tex = context.texture + + layout.itemR(tex, "use_color_ramp", text="Ramp") + if tex.use_color_ramp: + layout.template_color_ramp(tex.color_ramp, expand=True) + + split = layout.split() + + split.itemR(tex, "rgb_factor", text="Multiply RGB") + + col = split.column() + col.itemL(text="Adjust:") + col.itemR(tex, "brightness") + col.itemR(tex, "contrast") + +# Texture Slot Panels # + +class TextureSlotPanel(TextureButtonsPanel): + def poll(self, context): + return ( + context.texture_slot and + TextureButtonsPanel.poll(self, context) + ) + +class TEXTURE_PT_mapping(TextureSlotPanel): __label__ = "Mapping" - def poll(self, context): - return (context.texture_slot and context.texture and context.texture.type != 'NONE') - def draw(self, context): layout = self.layout @@ -150,12 +188,9 @@ class TEXTURE_PT_mapping(TextureButtonsPanel): row.column().itemR(tex, "offset") row.column().itemR(tex, "size") -class TEXTURE_PT_influence(TextureButtonsPanel): +class TEXTURE_PT_influence(TextureSlotPanel): __label__ = "Influence" - def poll(self, context): - return (context.texture_slot and context.texture and context.texture.type != 'NONE' and (not context.brush)) - def draw(self, context): layout = self.layout @@ -235,36 +270,16 @@ class TEXTURE_PT_influence(TextureButtonsPanel): if ma or wo: col.itemR(tex, "default_value", text="DVar", slider=True) -class TEXTURE_PT_colors(TextureButtonsPanel): - __label__ = "Colors" - __default_closed__ = True - - def draw(self, context): - layout = self.layout - - tex = context.texture - - layout.itemR(tex, "use_color_ramp", text="Ramp") - if tex.use_color_ramp: - layout.template_color_ramp(tex.color_ramp, expand=True) - - split = layout.split() - - split.itemR(tex, "rgb_factor", text="Multiply RGB") - - col = split.column() - col.itemL(text="Adjust:") - col.itemR(tex, "brightness") - col.itemR(tex, "contrast") - # Texture Type Panels # -class TEXTURE_PT_clouds(TextureButtonsPanel): - __label__ = "Clouds" - +class TextureTypePanel(TextureButtonsPanel): def poll(self, context): tex = context.texture - return (tex and tex.type == 'CLOUDS') + return (tex and tex.type == self.tex_type and not tex.use_nodes) + +class TEXTURE_PT_clouds(TextureTypePanel): + __label__ = "Clouds" + tex_type = 'CLOUDS' def draw(self, context): layout = self.layout @@ -281,12 +296,9 @@ class TEXTURE_PT_clouds(TextureButtonsPanel): flow.itemR(tex, "noise_depth", text="Depth") flow.itemR(tex, "nabla", text="Nabla") -class TEXTURE_PT_wood(TextureButtonsPanel): +class TEXTURE_PT_wood(TextureTypePanel): __label__ = "Wood" - - def poll(self, context): - tex = context.texture - return (tex and tex.type == 'WOOD') + tex_type = 'WOOD' def draw(self, context): layout = self.layout @@ -308,13 +320,10 @@ class TEXTURE_PT_wood(TextureButtonsPanel): flow.itemR(tex, "turbulence") flow.itemR(tex, "nabla") -class TEXTURE_PT_marble(TextureButtonsPanel): +class TEXTURE_PT_marble(TextureTypePanel): __label__ = "Marble" + tex_type = 'MARBLE' - def poll(self, context): - tex = context.texture - return (tex and tex.type == 'MARBLE') - def draw(self, context): layout = self.layout @@ -332,13 +341,10 @@ class TEXTURE_PT_marble(TextureButtonsPanel): flow.itemR(tex, "turbulence") flow.itemR(tex, "nabla") -class TEXTURE_PT_magic(TextureButtonsPanel): +class TEXTURE_PT_magic(TextureTypePanel): __label__ = "Magic" + tex_type = 'MAGIC' - def poll(self, context): - tex = context.texture - return (tex and tex.type == 'MAGIC') - def draw(self, context): layout = self.layout @@ -348,13 +354,10 @@ class TEXTURE_PT_magic(TextureButtonsPanel): row.itemR(tex, "noise_depth", text="Depth") row.itemR(tex, "turbulence") -class TEXTURE_PT_blend(TextureButtonsPanel): +class TEXTURE_PT_blend(TextureTypePanel): __label__ = "Blend" + tex_type = 'BLEND' - def poll(self, context): - tex = context.texture - return (tex and tex.type == 'BLEND') - def draw(self, context): layout = self.layout @@ -363,13 +366,10 @@ class TEXTURE_PT_blend(TextureButtonsPanel): layout.itemR(tex, "progression") layout.itemR(tex, "flip_axis") -class TEXTURE_PT_stucci(TextureButtonsPanel): +class TEXTURE_PT_stucci(TextureTypePanel): __label__ = "Stucci" + tex_type = 'STUCCI' - def poll(self, context): - tex = context.texture - return (tex and tex.type == 'STUCCI') - def draw(self, context): layout = self.layout @@ -384,13 +384,10 @@ class TEXTURE_PT_stucci(TextureButtonsPanel): row.itemR(tex, "noise_size", text="Size") row.itemR(tex, "turbulence") -class TEXTURE_PT_image(TextureButtonsPanel): +class TEXTURE_PT_image(TextureTypePanel): __label__ = "Image" + tex_type = 'IMAGE' - def poll(self, context): - tex = context.texture - return (tex and tex.type == 'IMAGE') - def draw(self, context): layout = self.layout @@ -398,14 +395,11 @@ class TEXTURE_PT_image(TextureButtonsPanel): layout.template_texture_image(tex) -class TEXTURE_PT_image_sampling(TextureButtonsPanel): +class TEXTURE_PT_image_sampling(TextureTypePanel): __label__ = "Image Sampling" __default_closed__ = True + tex_type = 'IMAGE' - def poll(self, context): - tex = context.texture - return (tex and tex.type == 'IMAGE') - def draw(self, context): layout = self.layout @@ -449,14 +443,11 @@ class TEXTURE_PT_image_sampling(TextureButtonsPanel): else: col.itemR(tex, "filter_eccentricity", text="Eccentricity") -class TEXTURE_PT_image_mapping(TextureButtonsPanel): +class TEXTURE_PT_image_mapping(TextureTypePanel): __label__ = "Image Mapping" __default_closed__ = True + tex_type = 'IMAGE' - def poll(self, context): - tex = context.texture - return (tex and tex.type == 'IMAGE') - def draw(self, context): layout = self.layout @@ -499,13 +490,10 @@ class TEXTURE_PT_image_mapping(TextureButtonsPanel): col.itemR(tex, "crop_max_x", text="X") col.itemR(tex, "crop_max_y", text="Y") -class TEXTURE_PT_plugin(TextureButtonsPanel): +class TEXTURE_PT_plugin(TextureTypePanel): __label__ = "Plugin" + tex_type = 'PLUGIN' - def poll(self, context): - tex = context.texture - return (tex and tex.type == 'PLUGIN') - def draw(self, context): layout = self.layout @@ -513,13 +501,10 @@ class TEXTURE_PT_plugin(TextureButtonsPanel): layout.itemL(text="Nothing yet") -class TEXTURE_PT_envmap(TextureButtonsPanel): +class TEXTURE_PT_envmap(TextureTypePanel): __label__ = "Environment Map" + tex_type = 'ENVIRONMENT_MAP' - def poll(self, context): - tex = context.texture - return (tex and tex.type == 'ENVIRONMENT_MAP') - def draw(self, context): layout = self.layout @@ -527,13 +512,10 @@ class TEXTURE_PT_envmap(TextureButtonsPanel): layout.itemL(text="Nothing yet") -class TEXTURE_PT_musgrave(TextureButtonsPanel): +class TEXTURE_PT_musgrave(TextureTypePanel): __label__ = "Musgrave" + tex_type = 'MUSGRAVE' - def poll(self, context): - tex = context.texture - return (tex and tex.type == 'MUSGRAVE') - def draw(self, context): layout = self.layout @@ -563,12 +545,9 @@ class TEXTURE_PT_musgrave(TextureButtonsPanel): row.itemR(tex, "noise_size", text="Size") row.itemR(tex, "nabla") -class TEXTURE_PT_voronoi(TextureButtonsPanel): +class TEXTURE_PT_voronoi(TextureTypePanel): __label__ = "Voronoi" - - def poll(self, context): - tex = context.texture - return (tex and tex.type == 'VORONOI') + tex_type = 'VORONOI' def draw(self, context): layout = self.layout @@ -600,13 +579,10 @@ class TEXTURE_PT_voronoi(TextureButtonsPanel): row.itemR(tex, "noise_size", text="Size") row.itemR(tex, "nabla") -class TEXTURE_PT_distortednoise(TextureButtonsPanel): +class TEXTURE_PT_distortednoise(TextureTypePanel): __label__ = "Distorted Noise" + tex_type = 'DISTORTED_NOISE' - def poll(self, context): - tex = context.texture - return (tex and tex.type == 'DISTORTED_NOISE') - def draw(self, context): layout = self.layout diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c index ccb5e5b2f95..76cb9986306 100644 --- a/source/blender/makesrna/intern/rna_texture.c +++ b/source/blender/makesrna/intern/rna_texture.c @@ -36,6 +36,9 @@ #include "DNA_material_types.h" #include "DNA_texture_types.h" #include "DNA_world_types.h" +#include "DNA_node_types.h" + +#include "BKE_node.h" #include "WM_types.h" @@ -107,6 +110,43 @@ static void rna_TextureSlot_name_get(PointerRNA *ptr, char *str) strcpy(str, ""); } +static EnumPropertyItem *rna_TextureSlot_output_node_itemf(bContext *C, PointerRNA *ptr, int *free) +{ + MTex *mtex= ptr->data; + Tex *tex= mtex->tex; + EnumPropertyItem *item= NULL; + int totitem= 0; + + if(tex) + { + bNodeTree *ntree= tex->nodetree; + if(ntree) + { + EnumPropertyItem tmp= {0, "", 0, "", ""}; + bNode *node; + + tmp.value = 0; + tmp.name = "Not Specified"; + tmp.identifier = "NOT_SPECIFIED"; + RNA_enum_item_add(&item, &totitem, &tmp); + + for(node= ntree->nodes.first; node; node= node->next) { + if(node->type == TEX_NODE_OUTPUT) { + tmp.value= node->custom1; + tmp.name= ((TexNodeOutput*)node->storage)->name; + tmp.identifier = tmp.name; + RNA_enum_item_add(&item, &totitem, &tmp); + } + } + } + } + + RNA_enum_item_end(&item, &totitem); + + *free = 1; + return item; +} + static void rna_Texture_use_color_ramp_set(PointerRNA *ptr, int value) { Tex *tex= (Tex*)ptr->data; @@ -118,6 +158,18 @@ static void rna_Texture_use_color_ramp_set(PointerRNA *ptr, int value) tex->coba= add_colorband(0); } +void rna_Texture_use_nodes_set(PointerRNA *ptr, int v) +{ + Tex *tex= (Tex*)ptr->data; + + tex->use_nodes = v; + tex->type = 0; + + if(v && tex->nodetree==NULL) { + node_texture_default(tex); + } +} + static void rna_ImageTexture_mipmap_set(PointerRNA *ptr, int value) { Tex *tex= (Tex*)ptr->data; @@ -287,6 +339,10 @@ static void rna_def_mtex(BlenderRNA *brna) {MTEX_MAP_MODE_3D, "3D", 0, "3D", ""}, {0, NULL, 0, NULL, NULL}}; + static EnumPropertyItem output_node_items[] = { + {0, "DUMMY", 0, "Dummy", ""}, + {0, NULL, 0, NULL, NULL}}; + srna= RNA_def_struct(brna, "TextureSlot", NULL); RNA_def_struct_sdna(srna, "MTex"); RNA_def_struct_ui_text(srna, "Texture Slot", "Texture slot defining the mapping and influence of a texture."); @@ -373,6 +429,13 @@ static void rna_def_mtex(BlenderRNA *brna) RNA_def_property_ui_range(prop, 0, 5, 10, 3); RNA_def_property_ui_text(prop, "Normal Factor", "Amount texture affects normal values."); RNA_def_property_update(prop, NC_TEXTURE, NULL); + + prop= RNA_def_property(srna, "output_node", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "which_output"); + RNA_def_property_enum_items(prop, output_node_items); + RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_TextureSlot_output_node_itemf"); + RNA_def_property_ui_text(prop, "Output Node", "Which output node to use, for node-based textures."); + RNA_def_property_update(prop, NC_TEXTURE, NULL); } static void rna_def_filter_size_common(StructRNA *srna) @@ -1285,7 +1348,19 @@ static void rna_def_texture(BlenderRNA *brna) RNA_def_property_range(prop, 0, 2); RNA_def_property_ui_text(prop, "RGB Factor", ""); RNA_def_property_update(prop, NC_TEXTURE, NULL); - + + /* nodetree */ + prop= RNA_def_property(srna, "use_nodes", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "use_nodes", 1); + RNA_def_property_boolean_funcs(prop, NULL, "rna_Texture_use_nodes_set"); + RNA_def_property_ui_text(prop, "Use Nodes", "Make this a node-based texture"); + RNA_def_property_update(prop, NC_TEXTURE, NULL); + + prop= RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "nodetree"); + RNA_def_property_ui_text(prop, "Node Tree", "Node tree for node-based textures"); + RNA_def_property_update(prop, NC_TEXTURE, NULL); + rna_def_animdata_common(srna); /* specific types */ diff --git a/source/blender/nodes/intern/TEX_nodes/TEX_output.c b/source/blender/nodes/intern/TEX_nodes/TEX_output.c index 060ea8d7e67..d0538d11900 100644 --- a/source/blender/nodes/intern/TEX_nodes/TEX_output.c +++ b/source/blender/nodes/intern/TEX_nodes/TEX_output.c @@ -64,11 +64,64 @@ static void exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) } } -static void init(bNode* node) +static void unique_name(bNode *node) { - TexNodeOutput *tno = MEM_callocN(sizeof(TexNodeOutput), "TEX_output"); - strcpy(tno->name, "Default"); - node->storage= tno; + TexNodeOutput *tno = (TexNodeOutput *)node->storage; + char *new_name = 0; + int new_len; + int suffix; + bNode *i; + char *name = tno->name; + + i = node; + while(i->prev) i = i->prev; + for(; i; i=i->next) { + if( + i == node || + i->type != TEX_NODE_OUTPUT || + strcmp(name, ((TexNodeOutput*)(i->storage))->name) + ) + continue; + + if(!new_name) { + int len = strlen(name); + if(len >= 4 && sscanf(name + len - 4, ".%03d", &suffix) == 1) { + new_len = len; + } else { + suffix = 0; + new_len = len + 4; + if(new_len > 31) + new_len = 31; + } + + new_name = malloc(new_len + 1); + strcpy(new_name, name); + name = new_name; + } + sprintf(new_name + new_len - 4, ".%03d", ++suffix); + } + + if(new_name) { + strcpy(tno->name, new_name); + free(new_name); + } +} + +static void init(bNode *node) +{ + TexNodeOutput *tno = MEM_callocN(sizeof(TexNodeOutput), "TEX_output"); + node->storage= tno; + + strcpy(tno->name, "Default"); + unique_name(node); + ntreeTexAssignIndex(0, node); +} + +static void copy(bNode *orig, bNode *new) +{ + node_copy_standard_storage(orig, new); + unique_name(new); + ntreeTexAssignIndex(0, new); } @@ -85,6 +138,6 @@ bNodeType tex_node_output= { /* butfunc */ NULL, /* initfunc */ init, /* freestoragefunc */ node_free_standard_storage, - /* copystoragefunc */ node_copy_standard_storage, + /* copystoragefunc */ copy, /* id */ NULL }; diff --git a/source/blender/nodes/intern/TEX_util.c b/source/blender/nodes/intern/TEX_util.c index 867e754f960..d25decd4111 100644 --- a/source/blender/nodes/intern/TEX_util.c +++ b/source/blender/nodes/intern/TEX_util.c @@ -197,6 +197,10 @@ void ntreeTexExecTree(bNodeTree *nodes, TexResult *texres, float *coord, char do TexResult dummy_texres; TexCallData data; + /* 0 means don't care, so just use first */ + if(which_output == 0) + which_output = 1; + if(!texres) texres = &dummy_texres; data.coord = coord; data.target = texres; @@ -270,10 +274,17 @@ char* ntreeTexOutputMenu(bNodeTree *ntree) void ntreeTexAssignIndex(struct bNodeTree *ntree, struct bNode *node) { bNode *tnode; - int index = 0; + int index = 1; + + if(ntree) + tnode = ntree->nodes.first; + else { + tnode = node; + while(tnode->prev) tnode = tnode->prev; + } check_index: - for(tnode= ntree->nodes.first; tnode; tnode= tnode->next) + for(; tnode; tnode= tnode->next) if(tnode->type == TEX_NODE_OUTPUT && tnode != node) if(tnode->custom1 == index) { index ++;