Group Nodes made functional: each group now can be re-used (instanced)

with SHIFT+G. This works as well for local groups as library-linked
groups.

Also fixed that group nodes were copying internal data to the outside,
which made it impossible to use the socket-buttons to set individual
values for each group-instance.

Library-linked groups are prevented from editing. But, try to open a
group and it will give a request for 'make local'. The make local rule
is identical to other library data in blender, meaning:
- if all users of the library data are local -> the library data is
  flagged 'local', and if needed a unique name is made
- if there's mixed users (local and from other library data) it makes
  a full copy, and assigns this copy to all local users.
This commit is contained in:
Ton Roosendaal 2006-02-07 15:50:55 +00:00
parent 03ae9e70b8
commit e4a0390b39
6 changed files with 278 additions and 82 deletions

@ -95,6 +95,7 @@ void ntreeInitTypes(struct bNodeTree *ntree);
void ntreeMakeOwnType(struct bNodeTree *ntree);
void ntreeFreeTree(struct bNodeTree *ntree);
struct bNodeTree *ntreeCopyTree(struct bNodeTree *ntree, int internal_select);
void ntreeMakeLocal(struct bNodeTree *ntree);
void ntreeSocketUseFlags(struct bNodeTree *ntree);

@ -358,7 +358,7 @@ static void curvemap_make_table(CurveMap *cuma, rctf *clipr)
if(cuma->table)
MEM_freeT(cuma->table);
totpoint= (cuma->totpoint-1)*CM_RESOL;
fp= allpoints= MEM_mallocT(totpoint*2*sizeof(float), "table");
fp= allpoints= MEM_callocT(totpoint*2*sizeof(float), "table");
for(a=0; a<cuma->totpoint-1; a++, fp += 2*CM_RESOL) {
correct_bezpart(bezt[a].vec[1], bezt[a].vec[2], bezt[a+1].vec[0], bezt[a+1].vec[1]);

@ -725,7 +725,10 @@ bNode *nodeAddNodeType(bNodeTree *ntree, int type, bNodeTree *ngroup)
BLI_addtail(&ntree->nodes, node);
node->typeinfo= ntype;
BLI_strncpy(node->name, ntype->name, NODE_MAXSTR);
if(ngroup)
BLI_strncpy(node->name, ngroup->id.name+2, NODE_MAXSTR);
else
BLI_strncpy(node->name, ntype->name, NODE_MAXSTR);
node->type= ntype->type;
node->flag= NODE_SELECT|ntype->flag;
node->width= ntype->width;
@ -868,6 +871,77 @@ bNodeTree *ntreeAddTree(int type)
return ntree;
}
bNodeTree *ntreeCopyTree(bNodeTree *ntree, int internal_select)
{
bNodeTree *newtree;
bNode *node, *nnode, *last;
bNodeLink *link, *nlink;
bNodeSocket *sock;
int a;
if(ntree==NULL) return NULL;
if(internal_select==0) {
/* is ntree part of library? */
for(newtree=G.main->nodetree.first; newtree; newtree= newtree->id.next)
if(newtree==ntree) break;
if(newtree)
newtree= copy_libblock(ntree);
else
newtree= MEM_dupallocN(ntree);
newtree->nodes.first= newtree->nodes.last= NULL;
newtree->links.first= newtree->links.last= NULL;
}
else
newtree= ntree;
last= ntree->nodes.last;
for(node= ntree->nodes.first; node; node= node->next) {
node->new= NULL;
if(internal_select==0 || (node->flag & NODE_SELECT)) {
nnode= nodeCopyNode(newtree, node); /* sets node->new */
if(internal_select) {
node->flag &= ~NODE_SELECT;
nnode->flag |= NODE_SELECT;
}
node->flag &= ~NODE_ACTIVE;
}
if(node==last) break;
}
/* check for copying links */
for(link= ntree->links.first; link; link= link->next) {
if(link->fromnode->new && link->tonode->new) {
nlink= nodeAddLink(newtree, link->fromnode->new, NULL, link->tonode->new, NULL);
/* sockets were copied in order */
for(a=0, sock= link->fromnode->outputs.first; sock; sock= sock->next, a++) {
if(sock==link->fromsock)
break;
}
nlink->fromsock= BLI_findlink(&link->fromnode->new->outputs, a);
for(a=0, sock= link->tonode->inputs.first; sock; sock= sock->next, a++) {
if(sock==link->tosock)
break;
}
nlink->tosock= BLI_findlink(&link->tonode->new->inputs, a);
}
}
/* own type definition for group usage */
if(internal_select==0) {
if(ntree->owntype) {
newtree->owntype= MEM_dupallocN(ntree->owntype);
if(ntree->owntype->inputs)
newtree->owntype->inputs= MEM_dupallocN(ntree->owntype->inputs);
if(ntree->owntype->outputs)
newtree->owntype->outputs= MEM_dupallocN(ntree->owntype->outputs);
}
}
return newtree;
}
#pragma mark /* ************** Free stuff ********** */
/* goes over entire tree */
@ -972,71 +1046,112 @@ void ntreeFreeTree(bNodeTree *ntree)
}
}
bNodeTree *ntreeCopyTree(bNodeTree *ntree, int internal_select)
void ntreeMakeLocal(bNodeTree *ntree)
{
bNodeTree *newtree;
bNode *node, *nnode, *last;
bNodeLink *link, *nlink;
bNodeSocket *sock;
int a;
int local=0, lib=0;
if(ntree==NULL) return NULL;
/* - only lib users: do nothing
* - only local users: set flag
* - mixed: make copy
*/
if(internal_select==0) {
newtree= MEM_dupallocN(ntree);
newtree->nodes.first= newtree->nodes.last= NULL;
newtree->links.first= newtree->links.last= NULL;
if(ntree->id.lib==NULL) return;
if(ntree->id.us==1) {
ntree->id.lib= 0;
ntree->id.flag= LIB_LOCAL;
new_id(0, (ID *)ntree, 0);
return;
}
else
newtree= ntree;
last= ntree->nodes.last;
for(node= ntree->nodes.first; node; node= node->next) {
/* now check users of groups... again typedepending, callback... */
if(ntree->type==NTREE_SHADER) {
Material *ma;
for(ma= G.main->mat.first; ma; ma= ma->id.next) {
if(ma->nodetree) {
bNode *node;
/* find if group is in tree */
for(node= ma->nodetree->nodes.first; node; node= node->next) {
if(node->id == (ID *)ntree) {
if(ma->id.lib) lib= 1;
else local= 1;
}
}
}
}
}
else if(ntree->type==NTREE_COMPOSIT) {
Scene *sce;
for(sce= G.main->scene.first; sce; sce= sce->id.next) {
if(sce->nodetree) {
bNode *node;
/* find if group is in tree */
for(node= sce->nodetree->nodes.first; node; node= node->next) {
if(node->id == (ID *)ntree) {
if(sce->id.lib) lib= 1;
else local= 1;
}
}
}
}
}
/* if all users are local, we simply make tree local */
if(local && lib==0) {
ntree->id.lib= NULL;
ntree->id.flag= LIB_LOCAL;
new_id(0, (ID *)ntree, 0);
}
else if(local && lib) {
/* this is the mixed case, we copy the tree and assign it to local users */
bNodeTree *newtree= ntreeCopyTree(ntree, 0);
node->new= NULL;
if(internal_select==0 || (node->flag & NODE_SELECT)) {
nnode= nodeCopyNode(newtree, node); /* sets node->new */
if(internal_select) {
node->flag &= ~NODE_SELECT;
nnode->flag |= NODE_SELECT;
newtree->id.us= 0;
if(ntree->type==NTREE_SHADER) {
Material *ma;
for(ma= G.main->mat.first; ma; ma= ma->id.next) {
if(ma->nodetree) {
bNode *node;
/* find if group is in tree */
for(node= ma->nodetree->nodes.first; node; node= node->next) {
if(node->id == (ID *)ntree) {
if(ma->id.lib==NULL) {
node->id= &newtree->id;
newtree->id.us++;
ntree->id.us--;
}
}
}
}
}
node->flag &= ~NODE_ACTIVE;
}
if(node==last) break;
}
/* check for copying links */
for(link= ntree->links.first; link; link= link->next) {
if(link->fromnode->new && link->tonode->new) {
nlink= nodeAddLink(newtree, link->fromnode->new, NULL, link->tonode->new, NULL);
/* sockets were copied in order */
for(a=0, sock= link->fromnode->outputs.first; sock; sock= sock->next, a++) {
if(sock==link->fromsock)
break;
else if(ntree->type==NTREE_COMPOSIT) {
Scene *sce;
for(sce= G.main->scene.first; sce; sce= sce->id.next) {
if(sce->nodetree) {
bNode *node;
/* find if group is in tree */
for(node= sce->nodetree->nodes.first; node; node= node->next) {
if(node->id == (ID *)ntree) {
if(sce->id.lib==NULL) {
node->id= &newtree->id;
newtree->id.us++;
ntree->id.us--;
}
}
}
}
}
nlink->fromsock= BLI_findlink(&link->fromnode->new->outputs, a);
for(a=0, sock= link->tonode->inputs.first; sock; sock= sock->next, a++) {
if(sock==link->tosock)
break;
}
nlink->tosock= BLI_findlink(&link->tonode->new->inputs, a);
}
}
/* own type definition for group usage */
if(internal_select==0) {
if(ntree->owntype) {
newtree->owntype= MEM_dupallocN(ntree->owntype);
if(ntree->owntype->inputs)
newtree->owntype->inputs= MEM_dupallocN(ntree->owntype->inputs);
if(ntree->owntype->outputs)
newtree->owntype->outputs= MEM_dupallocN(ntree->owntype->outputs);
}
}
return newtree;
}
#pragma mark /* ************ find stuff *************** */
bNodeLink *nodeFindLink(bNodeTree *ntree, bNodeSocket *from, bNodeSocket *to)
@ -1405,16 +1520,8 @@ static int ntree_begin_exec_tree(bNodeTree *ntree)
if(node->type==NODE_GROUP) {
if(node->id) {
node->stack_index= index;
index+= ntree_begin_exec_tree((bNodeTree *)node->id);
/* copy internal data from internal nodes to own input sockets */
for(sock= node->inputs.first; sock; sock= sock->next) {
if(sock->tosock) {
sock->ns= sock->tosock->ns;
}
}
}
}
}

@ -1203,7 +1203,7 @@ static void direct_link_curvemapping(FileData *fd, CurveMapping *cumap)
/* ************ READ NODE TREE *************** */
/* singe node tree, ntree is not NULL */
/* singe node tree (also used for material/scene trees), ntree is not NULL */
static void lib_link_ntree(FileData *fd, ID *id, bNodeTree *ntree)
{
bNode *node;
@ -1212,30 +1212,33 @@ static void lib_link_ntree(FileData *fd, ID *id, bNodeTree *ntree)
node->id= newlibadr_us(fd, id->lib, node->id);
}
/* library linking after fileread */
/* library ntree linking after fileread */
static void lib_link_nodetree(FileData *fd, Main *main)
{
bNodeTree *ntree;
/* only link ID pointers */
for(ntree= main->nodetree.first; ntree; ntree= ntree->id.next) {
if(ntree->id.flag & LIB_NEEDLINK) {
ntree->id.flag -= LIB_NEEDLINK;
lib_link_ntree(fd, &ntree->id, ntree);
}
}
}
/* verify types for nodes and groups, all data has to be read */
static void lib_verify_nodetree(Main *main)
{
Scene *sce;
Material *ma;
bNodeTree *ntree;
bNode *node;
/* in multiple steps, first link ID pointers */
for(ntree= main->nodetree.first; ntree; ntree= ntree->id.next) {
if(ntree->id.flag & LIB_NEEDLINK) {
lib_link_ntree(fd, &ntree->id, ntree);
}
}
/* now create the own typeinfo structs an verify nodes */
/* here we still assume no groups in groups */
for(ntree= main->nodetree.first; ntree; ntree= ntree->id.next) {
if(ntree->id.flag & LIB_NEEDLINK) {
ntree->id.flag -= LIB_NEEDLINK;
ntreeVerifyTypes(ntree); /* internal nodes, no groups! */
ntreeMakeOwnType(ntree); /* for group usage */
}
ntreeVerifyTypes(ntree); /* internal nodes, no groups! */
ntreeMakeOwnType(ntree); /* for group usage */
}
/* now verify all types in material trees, groups are set OK now */
@ -1250,6 +1253,8 @@ static void lib_link_nodetree(FileData *fd, Main *main)
}
}
/* ntree itself has been read! */
static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
{
@ -5370,7 +5375,7 @@ static void lib_link_all(FileData *fd, Main *main)
lib_link_armature(fd, main);
lib_link_action(fd, main);
lib_link_vfont(fd, main);
lib_link_nodetree(fd, main); /* has to be done after materials, it will verify group nodes */
lib_link_nodetree(fd, main); /* has to be done after scene/materials, this will verify group nodes */
lib_link_mesh(fd, main); /* as last: tpage images with users at zero */
@ -5453,6 +5458,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, BlendReadError *error_r)
blo_join_main(&fd->mainlist);
lib_link_all(fd, bfd->main);
lib_verify_nodetree(bfd->main);
link_global(fd, bfd, fg); /* as last */
@ -5936,6 +5942,9 @@ static void expand_scene(FileData *fd, Main *mainvar, Scene *sce)
}
expand_doit(fd, mainvar, sce->camera);
expand_doit(fd, mainvar, sce->world);
if(sce->nodetree)
expand_nodetree(fd, mainvar, sce->nodetree);
}
static void expand_camera(FileData *fd, Main *mainvar, Camera *ca)
@ -6175,6 +6184,7 @@ void BLO_script_library_append(BlendHandle *bh, char *dir, char *name, int idcod
G.main= mainlist.first;
lib_link_all(fd, G.main);
lib_verify_nodetree(G.main);
DAG_scene_sort(G.scene);
}
@ -6259,6 +6269,7 @@ void BLO_library_append(SpaceFile *sfile, char *dir, int idcode)
G.main= fd->mainlist.first;
lib_link_all(fd, G.main);
lib_verify_nodetree(G.main);
/* give a base to loose objects */
give_base_to_objects(G.scene, &(G.main->object), sfile->flag & FILE_LINK);

@ -1361,7 +1361,16 @@ static void node_draw_basis(ScrArea *sa, SpaceNode *snode, bNode *node)
iconofs-= 18.0f;
glEnable(GL_BLEND);
BIF_icon_set_aspect(ICON_NODE, snode->aspect);
BIF_icon_draw_blended(iconofs, rct->ymax-NODE_DY+2, ICON_NODE, 0, -60);
if(node->id->lib) {
glPixelTransferf(GL_GREEN_SCALE, 0.7f);
glPixelTransferf(GL_BLUE_SCALE, 0.3f);
BIF_icon_draw(iconofs, rct->ymax-NODE_DY+2, ICON_NODE);
glPixelTransferf(GL_GREEN_SCALE, 1.0f);
glPixelTransferf(GL_BLUE_SCALE, 1.0f);
}
else {
BIF_icon_draw_blended(iconofs, rct->ymax-NODE_DY+2, ICON_NODE, 0, -60);
}
glDisable(GL_BLEND);
}
if(node->typeinfo->flag & NODE_OPTIONS) {
@ -1443,9 +1452,6 @@ static void node_draw_basis(ScrArea *sa, SpaceNode *snode, bNode *node)
if(node->block && sock->link==NULL) {
float *butpoin= sock->ns.vec;
if(node->type==NODE_GROUP && sock->tosock)
butpoin= sock->tosock->ns.vec;
if(sock->type==SOCK_VALUE) {
bt= uiDefButF(node->block, NUM, B_NODE_EXEC+node->nr, sock->name,
(short)sock->locx+NODE_DYS, (short)(sock->locy)-9, (short)node->width-NODE_DY, 17,

@ -420,6 +420,12 @@ static void snode_make_group_editable(SpaceNode *snode, bNode *gnode)
}
if(gnode && gnode->type==NODE_GROUP && gnode->id) {
if(gnode->id->lib) {
if(okee("Make Group Local"))
ntreeMakeLocal((bNodeTree *)gnode->id);
else
return;
}
gnode->flag |= NODE_GROUP_EDIT;
snode->edittree= (bNodeTree *)gnode->id;
@ -432,6 +438,8 @@ static void snode_make_group_editable(SpaceNode *snode, bNode *gnode)
else
snode->edittree= snode->nodetree;
ntreeSolveOrder(snode->nodetree);
/* finally send out events for new active node */
if(snode->treetype==NTREE_SHADER) {
allqueue(REDRAWBUTSSHADING, 0);
@ -474,6 +482,66 @@ static void snode_verify_groups(SpaceNode *snode)
}
static void node_addgroup(SpaceNode *snode)
{
bNodeTree *ngroup;
int tot= 0, offs, val;
char *strp;
if(snode->edittree!=snode->nodetree) {
error("Can not add a Group in a Group");
return;
}
/* construct menu with choices */
for(ngroup= G.main->nodetree.first; ngroup; ngroup= ngroup->id.next) {
if(ngroup->type==snode->treetype)
tot++;
}
if(tot==0) {
error("No groups available in database");
return;
}
strp= MEM_mallocN(32*tot+32, "menu");
strcpy(strp, "Add Group %t");
offs= strlen(strp);
for(tot=0, ngroup= G.main->nodetree.first; ngroup; ngroup= ngroup->id.next, tot++) {
if(ngroup->type==snode->treetype)
offs+= sprintf(strp+offs, "|%s %%x%d", ngroup->id.name+2, tot);
}
val= pupmenu(strp);
if(val>=0) {
ngroup= BLI_findlink(&G.main->nodetree, val);
if(ngroup) {
bNode *node= nodeAddNodeType(snode->edittree, NODE_GROUP, ngroup);
/* generics */
if(node) {
float locx, locy;
short mval[2];
node_deselectall(snode, 0);
getmouseco_areawin(mval);
areamouseco_to_ipoco(G.v2d, mval, &locx, &locy);
node->locx= locx;
node->locy= locy + 60.0f; // arbitrary.. so its visible
node->flag |= SELECT;
id_us_plus(node->id);
node_set_active(snode, node);
BIF_undo_push("Add Node");
}
}
}
MEM_freeN(strp);
}
/* ************************** Node generic ************** */
/* allows to walk the list in order of visibility */
@ -1737,6 +1805,9 @@ void winqreadnodespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
if(okee("Ungroup"))
node_ungroup(snode);
}
else if(G.qual==LR_SHIFTKEY) {
node_addgroup(snode);
}
else
transform_nodes(snode->edittree, 'g', "Translate Node");
}