Cycles: svn merge -r40266:40358 https://svn.blender.org/svnroot/bf-blender/trunk...
[blender-staging.git] / source / blender / editors / space_node / node_edit.c
index b5633d509979f2764defcc44432710b277e0cac9..2490bd33101b81121e7ce58068d38a7e40eb6afa 100644 (file)
 #include "MEM_guardedalloc.h"
 
 #include "DNA_ID.h"
-#include "DNA_object_types.h"
+#include "DNA_lamp_types.h"
 #include "DNA_material_types.h"
 #include "DNA_node_types.h"
+#include "DNA_object_types.h"
 #include "DNA_particle_types.h"
 #include "DNA_scene_types.h"
+#include "DNA_world_types.h"
 
 #include "BLI_math.h"
 #include "BLI_blenlib.h"
@@ -95,6 +97,8 @@
 
 #include "RNA_enum_types.h"
 
+#include "GPU_material.h"
+
 #include "node_intern.h"
 
 static EnumPropertyItem socket_in_out_items[] = {
@@ -275,36 +279,57 @@ bNode *node_tree_get_editgroup(bNodeTree *nodetree)
 
 /* assumes nothing being done in ntree yet, sets the default in/out node */
 /* called from shading buttons or header */
-void ED_node_shader_default(Material *ma)
+void ED_node_shader_default(ID *id)
 {
        bNode *in, *out;
        bNodeSocket *fromsock, *tosock;
+       bNodeTree *ntree;
        bNodeTemplate ntemp;
+       int output_type, shader_type;
        
-       /* but lets check it anyway */
-       if(ma->nodetree) {
-               if (G.f & G_DEBUG)
-                       printf("error in shader initialize\n");
-               return;
+       ntree= ntreeAddTree("Shader Nodetree", NTREE_SHADER, 0);
+
+       switch(GS(id->name)) {
+               case ID_MA:
+                       ((Material*)id)->nodetree = ntree;
+                       output_type = SH_NODE_OUTPUT_MATERIAL;
+                       shader_type = SH_NODE_BSDF_DIFFUSE;
+                       break;
+               case ID_WO:
+                       ((World*)id)->nodetree = ntree;
+                       output_type = SH_NODE_OUTPUT_WORLD;
+                       shader_type = SH_NODE_BACKGROUND;
+                       break;
+               case ID_LA:
+                       ((Lamp*)id)->nodetree = ntree;
+                       output_type = SH_NODE_OUTPUT_LAMP;
+                       shader_type = SH_NODE_EMISSION;
+                       break;
+               case ID_TE:
+                       ((Tex*)id)->nodetree = ntree;
+                       output_type = SH_NODE_OUTPUT_TEXTURE;
+                       shader_type = SH_NODE_TEX_CLOUDS;
+                       break;
+               default:
+                       printf("ED_node_shader_default called on wrong ID type.\n");
+                       return;
        }
        
-       ma->nodetree= ntreeAddTree("Shader Nodetree", NTREE_SHADER, 0);
-       
-       ntemp.type = SH_NODE_OUTPUT;
-       out= nodeAddNode(ma->nodetree, &ntemp);
+       ntemp.type = output_type;
+       out= nodeAddNode(ntree, &ntemp);
        out->locx= 300.0f; out->locy= 300.0f;
        
-       ntemp.type = SH_NODE_MATERIAL;
-       in= nodeAddNode(ma->nodetree, &ntemp);
+       ntemp.type = shader_type;
+       in= nodeAddNode(ntree, &ntemp);
        in->locx= 10.0f; in->locy= 300.0f;
-       nodeSetActive(ma->nodetree, in);
+       nodeSetActive(ntree, in);
        
        /* only a link from color to color */
        fromsock= in->outputs.first;
        tosock= out->inputs.first;
-       nodeAddLink(ma->nodetree, in, fromsock, out, tosock);
+       nodeAddLink(ntree, in, fromsock, out, tosock);
        
-       ntreeUpdateTree(ma->nodetree);
+       ntreeUpdateTree(ntree);
 }
 
 /* assumes nothing being done in ntree yet, sets the default in/out node */
@@ -351,6 +376,9 @@ void ED_node_composit_default(Scene *sce)
 /* called from shading buttons or header */
 void ED_node_texture_default(Tex *tx)
 {
+       ED_node_shader_default(&tx->id);
+
+#if 0
        bNode *in, *out;
        bNodeSocket *fromsock, *tosock;
        bNodeTemplate ntemp;
@@ -378,6 +406,7 @@ void ED_node_texture_default(Tex *tx)
        nodeAddLink(tx->nodetree, in, fromsock, out, tosock);
        
        ntreeUpdateTree(tx->nodetree);
+#endif
 }
 
 /* id is supposed to contain a node tree */
@@ -395,13 +424,21 @@ void node_tree_from_ID(ID *id, bNodeTree **ntree, bNodeTree **edittree, int *tre
                        *ntree= ((Material*)id)->nodetree;
                        if(treetype) *treetype= NTREE_SHADER;
                }
+               else if(idtype == ID_LA) {
+                       *ntree= ((Lamp*)id)->nodetree;
+                       if(treetype) *treetype= NTREE_SHADER;
+               }
+               else if(idtype == ID_WO) {
+                       *ntree= ((World*)id)->nodetree;
+                       if(treetype) *treetype= NTREE_SHADER;
+               }
                else if(idtype == ID_SCE) {
                        *ntree= ((Scene*)id)->nodetree;
                        if(treetype) *treetype= NTREE_COMPOSIT;
                }
                else if(idtype == ID_TE) {
                        *ntree= ((Tex*)id)->nodetree;
-                       if(treetype) *treetype= NTREE_TEXTURE;
+                       if(treetype) *treetype= (*ntree)? (*ntree)->type: NTREE_SHADER;
                }
                else {
                        if(treetype) *treetype= 0;
@@ -436,20 +473,33 @@ void snode_set_context(SpaceNode *snode, Scene *scene)
        
        if(snode->treetype==NTREE_SHADER) {
                /* need active object, or we allow pinning... */
-               if(ob) {
-                       Material *ma= give_current_material(ob, ob->actcol);
-                       if(ma) {
-                               snode->from= &ob->id;
-                               snode->id= &ma->id;
+               if(snode->shaderfrom == SNODE_SHADER_OBJECT) {
+                       if(ob) {
+                               if(ob->type == OB_LAMP) {
+                                       snode->from= &ob->id;
+                                       snode->id= ob->data;
+                               }
+                               else {
+                                       Material *ma= give_current_material(ob, ob->actcol);
+                                       if(ma) {
+                                               snode->from= &ob->id;
+                                               snode->id= &ma->id;
+                                       }
+                               }
+                       }
+               }
+               else { /* SNODE_SHADER_WORLD */
+                       if(scene->world) {
+                               snode->from= NULL;
+                               snode->id= &scene->world->id;
                        }
                }
        }
        else if(snode->treetype==NTREE_COMPOSIT) {
                snode->id= &scene->id;
                
-               /* bit clumsy but reliable way to see if we draw first time */
-               if(snode->nodetree==NULL)
-                       ntreeCompositForceHidden(scene->nodetree, scene);
+               /* update output sockets based on available layers */
+               ntreeCompositForceHidden(scene->nodetree, scene);
        }
        else if(snode->treetype==NTREE_TEXTURE) {
                Tex *tx= NULL;
@@ -527,6 +577,8 @@ static int has_nodetree(bNodeTree *ntree, bNodeTree *lookup)
 
 void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
 {
+       int was_active_texture = (node->flag & NODE_ACTIVE_TEXTURE);
+
        nodeSetActive(ntree, node);
        
        if(node->type!=NODE_GROUP) {
@@ -535,7 +587,7 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
                /* tree specific activate calls */
                if(ntree->type==NTREE_SHADER) {
                        /* when we select a material, active texture is cleared, for buttons */
-                       if(node->id && GS(node->id->name)==ID_MA)
+                       if(node->id && ELEM3(GS(node->id->name), ID_MA, ID_LA, ID_WO))
                                nodeClearActiveID(ntree, ID_TE);
                        
                        if(node->type==SH_NODE_OUTPUT) {
@@ -550,6 +602,15 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
                                        ED_node_generic_update(bmain, ntree, node);
                        }
 
+                       /* if active texture changed, free glsl materials */
+                       if((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) {
+                               Material *ma;
+
+                               for(ma=bmain->mat.first; ma; ma=ma->id.next)
+                                       if(ma->nodetree && ma->use_nodes && has_nodetree(ma->nodetree, ntree))
+                                               GPU_material_free(ma);
+                       }
+
                        WM_main_add_notifier(NC_MATERIAL|ND_NODES, node->id);
                }
                else if(ntree->type==NTREE_COMPOSIT) {
@@ -608,28 +669,45 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
 static int compare_nodes(bNode *a, bNode *b)
 {
        bNode *parent;
+       /* These tell if either the node or any of the parent nodes is selected.
+        * A selected parent means an unselected node is also in foreground!
+        */
+       int a_select=(a->flag & NODE_SELECT), b_select=(b->flag & NODE_SELECT);
+       int a_active=(a->flag & NODE_ACTIVE), b_active=(b->flag & NODE_ACTIVE);
        
        /* if one is an ancestor of the other */
        /* XXX there might be a better sorting algorithm for stable topological sort, this is O(n^2) worst case */
        for (parent = a->parent; parent; parent=parent->parent) {
+               /* if b is an ancestor, it is always behind a */
                if (parent==b)
                        return 1;
+               /* any selected ancestor moves the node forward */
+               if (parent->flag & NODE_ACTIVE)
+                       a_active = 1;
+               if (parent->flag & NODE_SELECT)
+                       a_select = 1;
        }
        for (parent = b->parent; parent; parent=parent->parent) {
+               /* if a is an ancestor, it is always behind b */
                if (parent==a)
                        return 0;
+               /* any selected ancestor moves the node forward */
+               if (parent->flag & NODE_ACTIVE)
+                       b_active = 1;
+               if (parent->flag & NODE_SELECT)
+                       b_select = 1;
        }
 
        /* if one of the nodes is in the background and the other not */
-       if ((a->flag & NODE_BACKGROUND) && !(b->typeinfo->flag & NODE_BACKGROUND))
+       if ((a->flag & NODE_BACKGROUND) && !(b->flag & NODE_BACKGROUND))
                return 0;
-       else if (!(a->flag & NODE_BACKGROUND) && (b->typeinfo->flag & NODE_BACKGROUND))
+       else if (!(a->flag & NODE_BACKGROUND) && (b->flag & NODE_BACKGROUND))
                return 1;
        
        /* if one has a higher selection state (active > selected > nothing) */
-       if (!(b->flag & NODE_ACTIVE) && (a->flag & NODE_ACTIVE))
+       if (!b_active && a_active)
                return 1;
-       else if (!(b->flag & NODE_SELECT) && ((a->flag & NODE_ACTIVE) || (a->flag & NODE_SELECT)))
+       else if (!b_select && (a_active || a_select))
                return 1;
        
        return 0;
@@ -776,7 +854,7 @@ static int edit_node_invoke_properties(bContext *C, wmOperator *op)
 static void edit_node_properties_get(wmOperator *op, bNodeTree *ntree, bNode **rnode, bNodeSocket **rsock, int *rin_out)
 {
        bNode *node;
-       bNodeSocket *sock;
+       bNodeSocket *sock=NULL;
        char nodename[32];
        int sockindex;
        int in_out;
@@ -967,7 +1045,7 @@ void NODE_OT_group_socket_remove(wmOperatorType *ot)
 {
        /* identifiers */
        ot->name = "Remove Group Socket";
-       ot->description = "Removed node group socket";
+       ot->description = "Remove a node group socket";
        ot->idname = "NODE_OT_group_socket_remove";
        
        /* api callbacks */
@@ -3446,7 +3524,7 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
                ima= BKE_add_image_file(path);
 
                if(!ima) {
-                       BKE_reportf(op->reports, RPT_ERROR, "Can't read: \"%s\", %s.", path, errno ? strerror(errno) : "Unsupported image format");
+                       BKE_reportf(op->reports, RPT_ERROR, "Can't read: \"%s\", %s", path, errno ? strerror(errno) : "Unsupported image format");
                        return OPERATOR_CANCELLED;
                }
        }
@@ -3457,7 +3535,7 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
                ima= (Image *)find_id("IM", name);
 
                if(!ima) {
-                       BKE_reportf(op->reports, RPT_ERROR, "Image named \"%s\", not found.", name);
+                       BKE_reportf(op->reports, RPT_ERROR, "Image named \"%s\", not found", name);
                        return OPERATOR_CANCELLED;
                }
        }
@@ -3475,7 +3553,7 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
        node = node_add_node(snode, bmain, scene, &ntemp, snode->mx, snode->my);
        
        if (!node) {
-               BKE_report(op->reports, RPT_WARNING, "Could not add an image node.");
+               BKE_report(op->reports, RPT_WARNING, "Could not add an image node");
                return OPERATOR_CANCELLED;
        }
        
@@ -3518,7 +3596,38 @@ void NODE_OT_add_file(wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
        WM_operator_properties_filesel(ot, FOLDERFILE|IMAGEFILE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH);  //XXX TODO, relative_path
-       RNA_def_string(ot->srna, "name", "Image", 24, "Name", "Datablock name to assign.");
+       RNA_def_string(ot->srna, "name", "Image", 24, "Name", "Datablock name to assign");
+}
+
+/* ****************** Auto Layout Operator  ******************* */
+
+static int node_auto_layout_exec(bContext *C, wmOperator *UNUSED(op))
+{
+       SpaceNode *snode= CTX_wm_space_node(C);
+       bNode *node;
+
+       for(node=snode->edittree->nodes.first; node; node=node->next)
+               if(node->flag & SELECT)
+                       ED_node_tree_auto_layout(snode->edittree, node);
+
+       snode_notify(C, snode);
+       
+       return OPERATOR_FINISHED;
+}
+
+void NODE_OT_auto_layout(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Auto Layout Nodes";
+       ot->description= "Automatically layout nodes with the selected nodes as root";
+       ot->idname= "NODE_OT_auto_layout";
+       
+       /* callbacks */
+       ot->exec= node_auto_layout_exec;
+       ot->poll= ED_operator_node_active;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
 /********************** New node tree operator *********************/
@@ -3549,7 +3658,6 @@ static int new_node_tree_exec(bContext *C, wmOperator *op)
        
        /* hook into UI */
        uiIDContextProperty(C, &ptr, &prop);
-
        if(prop) {
                RNA_id_pointer_create(&ntree->id, &idptr);
                RNA_property_pointer_set(&ptr, prop, idptr);
@@ -3585,3 +3693,4 @@ void NODE_OT_new_node_tree(wmOperatorType *ot)
        RNA_def_enum(ot->srna, "type", nodetree_type_items, NTREE_COMPOSIT, "Tree Type", "");
        RNA_def_string(ot->srna, "name", "NodeTree", MAX_ID_NAME-2, "Name", "");
 }
+