static bNode *node_group_make_from_selected(const bContext *C, bNodeTree *ntree, const char *ntype, const char *ntreetype) { Main *bmain = CTX_data_main(C); bNode *gnode; bNodeTree *ngroup; float min[2], max[2]; int totselect; totselect = node_get_selected_minmax(ntree, NULL, min, max); /* don't make empty group */ if (totselect == 0) return NULL; /* new nodetree */ ngroup = ntreeAddTree(bmain, "NodeGroup", ntreetype); /* make group node */ gnode = nodeAddNode(C, ntree, ntype); gnode->id = (ID *)ngroup; gnode->locx = 0.5f * (min[0] + max[0]); gnode->locy = 0.5f * (min[1] + max[1]); node_group_make_insert_selected(C, ntree, gnode); /* update of the tree containing the group instance node */ ntree->update |= NTREE_UPDATE_NODES; return gnode; }
/* /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// */ static MatItem *mat_livedb_add_mat_element(Main *bmain, bContext *C, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to, MatItem **_item, char* file_path, float x_pos, float *y_pos) { MatItem *ptr; MatItem *item = *_item; char tex_file_name[1024]; bNodeSocket *sock; switch (item->type) { case MAT_LDB_VALUE_TYPE_EMPTY: { *_item = (MatItem*)((char*)item + item->size); break; } case MAT_LDB_VALUE_TYPE_FLINK: { ptr = (MatItem*) ((char*)item - item->uint_vector[0]); mat_livedb_add_mat_element(bmain, C, ntree, node_to, 0, &ptr, file_path, 0, 0); *_item = (MatItem*)((char*)item + item->size); break; } case MAT_LDB_VALUE_TYPE_NLINK: { bNode *linked_node = *((bNode**) ((MatItem*)((char*)item - item->uint_vector[0]))->data); connect_node(bmain, ntree, linked_node, node_to, sock_to); *_item = (MatItem*)((char*)item + item->size); break; } case MAT_LDB_VALUE_TYPE_NODE: { if(sock_to->type == SOCK_FLOAT && sock_to->default_value && !strcmp(item->data, "ShaderNodeOctFloatTex")) { item = (MatItem*)((char*)item + item->size); ((bNodeSocketValueFloat*)sock_to->default_value)->value = item->float_vector[0]; *_item = (MatItem*)((char*)item + item->size); } else if(sock_to->type == SOCK_RGBA && sock_to->default_value && !strcmp(item->data, "ShaderNodeOctRGBSpectrumTex")) { item = (MatItem*)((char*)item + item->size); ((bNodeSocketValueRGBA*)sock_to->default_value)->value[0] = item->float_vector[0]; ((bNodeSocketValueRGBA*)sock_to->default_value)->value[1] = item->float_vector[1]; ((bNodeSocketValueRGBA*)sock_to->default_value)->value[2] = item->float_vector[2]; ((bNodeSocketValueRGBA*)sock_to->default_value)->value[3] = item->float_vector[3]; *_item = (MatItem*)((char*)item + item->size); } else { float cur_y_pos; int node_height = U.widget_unit; bool childs_present = false; bNode *node_fr = nodeAddNode(C, ntree, item->data); connect_node(bmain, ntree, node_fr, node_to, sock_to); *_item = (MatItem*)((char*)item + item->size); ptr = *_item; *((bNode**)item->data) = node_fr; if(node_fr->type == SH_NODE_OCT_IMAGE_TEX || node_fr->type == SH_NODE_OCT_FLOAT_IMAGE_TEX || node_fr->type == SH_NODE_OCT_ALPHA_IMAGE_TEX) { mat_livedb_add_mat_element(bmain, C, ntree, node_fr, 0, &ptr, file_path, 0, 0); node_height += (U.widget_unit * 2.5); } node_fr->locx = x_pos - node_fr->width - LDB_NODES_H_GAP; node_fr->locy = cur_y_pos = *y_pos; for (sock = node_fr->inputs.first; sock; sock = sock->next) { if(!sock) continue; if(!childs_present) childs_present = true; node_height += U.widget_unit; mat_livedb_add_mat_element(bmain, C, ntree, node_fr, sock, &ptr, file_path, node_fr->locx, &cur_y_pos); } if(node_fr->type == SH_NODE_OCT_GRADIENT_TEX) { mat_livedb_add_mat_element(bmain, C, ntree, node_fr, 0, &ptr, file_path, 0, 0); node_height += (U.widget_unit * 2.5); } *_item = ptr; *y_pos -= (node_height + LDB_NODES_V_GAP); if(childs_present) *y_pos = (*y_pos < cur_y_pos ? *y_pos : cur_y_pos); } break; } case MAT_LDB_VALUE_TYPE_INT: if(sock_to->default_value) ((bNodeSocketValueInt*)sock_to->default_value)->value = item->int_vector[0]; *_item = (MatItem*)((char*)item + item->size); break; case MAT_LDB_VALUE_TYPE_INT2: if(sock_to->default_value) { ((bNodeSocketValueVector*)sock_to->default_value)->value[0] = item->int_vector[0]; ((bNodeSocketValueVector*)sock_to->default_value)->value[1] = item->int_vector[1]; } *_item = (MatItem*)((char*)item + item->size); break; case MAT_LDB_VALUE_TYPE_INT3: if(sock_to->default_value) { ((bNodeSocketValueVector*)sock_to->default_value)->value[0] = item->int_vector[0]; ((bNodeSocketValueVector*)sock_to->default_value)->value[1] = item->int_vector[1]; ((bNodeSocketValueVector*)sock_to->default_value)->value[2] = item->int_vector[2]; } *_item = (MatItem*)((char*)item + item->size); break; case MAT_LDB_VALUE_TYPE_INT4: if(sock_to->default_value) { ((bNodeSocketValueRGBA*)sock_to->default_value)->value[0] = item->int_vector[0]; ((bNodeSocketValueRGBA*)sock_to->default_value)->value[1] = item->int_vector[1]; ((bNodeSocketValueRGBA*)sock_to->default_value)->value[2] = item->int_vector[2]; ((bNodeSocketValueRGBA*)sock_to->default_value)->value[3] = item->int_vector[3]; } *_item = (MatItem*)((char*)item + item->size); break; case MAT_LDB_VALUE_TYPE_FLOAT: if(sock_to->default_value) ((bNodeSocketValueFloat*)sock_to->default_value)->value = item->float_vector[0]; *_item = (MatItem*)((char*)item + item->size); break; case MAT_LDB_VALUE_TYPE_FLOAT2: if(sock_to->default_value) { ((bNodeSocketValueVector*)sock_to->default_value)->value[0] = item->float_vector[0]; ((bNodeSocketValueVector*)sock_to->default_value)->value[1] = item->float_vector[1]; } *_item = (MatItem*)((char*)item + item->size); break; case MAT_LDB_VALUE_TYPE_FLOAT3: if(sock_to->default_value) { ((bNodeSocketValueVector*)sock_to->default_value)->value[0] = item->float_vector[0]; ((bNodeSocketValueVector*)sock_to->default_value)->value[1] = item->float_vector[1]; ((bNodeSocketValueVector*)sock_to->default_value)->value[2] = item->float_vector[2]; } *_item = (MatItem*)((char*)item + item->size); break; case MAT_LDB_VALUE_TYPE_FLOAT4: if(sock_to->default_value) { ((bNodeSocketValueRGBA*)sock_to->default_value)->value[0] = item->float_vector[0]; ((bNodeSocketValueRGBA*)sock_to->default_value)->value[1] = item->float_vector[1]; ((bNodeSocketValueRGBA*)sock_to->default_value)->value[2] = item->float_vector[2]; ((bNodeSocketValueRGBA*)sock_to->default_value)->value[3] = item->float_vector[3]; } *_item = (MatItem*)((char*)item + item->size); break; case MAT_LDB_VALUE_TYPE_BOOL: if(sock_to->default_value) ((bNodeSocketValueBoolean*)sock_to->default_value)->value = item->int_vector[0]; *_item = (MatItem*)((char*)item + item->size); break; case MAT_LDB_VALUE_TYPE_STRING: if(sock_to->default_value) strcpy(((bNodeSocketValueString*)sock_to->default_value)->value, item->data); *_item = (MatItem*)((char*)item + item->size); break; case MAT_LDB_VALUE_TYPE_COLOR: if(sock_to->default_value) { ((bNodeSocketValueRGBA*)sock_to->default_value)->value[0] = item->float_vector[0]; ((bNodeSocketValueRGBA*)sock_to->default_value)->value[1] = item->float_vector[1]; ((bNodeSocketValueRGBA*)sock_to->default_value)->value[2] = item->float_vector[2]; ((bNodeSocketValueRGBA*)sock_to->default_value)->value[3] = item->float_vector[3]; } *_item = (MatItem*)((char*)item + item->size); break; case MAT_LDB_VALUE_TYPE_FILE: { char* file_name; FILE *file; struct Image *ima = (struct Image*)node_to->id; file_name = item->data + sizeof(uint32_t); if(file_name[0]) { strcpy(tex_file_name, file_path); strcat(tex_file_name, file_name); file = BLI_fopen(tex_file_name, "rb"); if(!file) { file = BLI_fopen(tex_file_name, "wb"); if(file) { if(!fwrite(item->data + sizeof(uint32_t) + strlen(file_name) + 1, *((uint32_t*)item->data), 1, file)) { } fclose(file); } } else fclose(file); } else tex_file_name[0] = 0; if(!ima) node_to->id = (struct ID*)BKE_image_load_exists(tex_file_name); *_item = (MatItem*)((char*)item + item->size); break; } case MAT_LDB_VALUE_TYPE_RAMP: { char* file_name; FILE *file; struct ColorBand *coba = (struct ColorBand*)node_to->storage; RampItem *ramp_item = (RampItem*)item->data; if(coba && ramp_item->pos_cnt > 1) { int i; coba->tot = ramp_item->pos_cnt; for(i = 0; i < ramp_item->pos_cnt; ++i) { coba->data[i].pos = ramp_item->pos_data[i * 4 + 0]; coba->data[i].r = ramp_item->pos_data[i * 4 + 1]; coba->data[i].g = ramp_item->pos_data[i * 4 + 2]; coba->data[i].b = ramp_item->pos_data[i * 4 + 3]; coba->data[i].a = 1.0; } } *_item = (MatItem*)((char*)item + item->size); break; } default: break; } return *_item; } /* mat_livedb_add_mat_element */
bNode *node_group_make_from_selected(bNodeTree *ntree) { bNodeLink *link, *linkn; bNode *node, *gnode, *nextn; bNodeTree *ngroup; bNodeSocket *gsock; ListBase anim_basepaths = {NULL, NULL}; float min[2], max[2]; int totnode=0; bNodeTemplate ntemp; INIT_MINMAX2(min, max); /* is there something to group? also do some clearing */ for(node= ntree->nodes.first; node; node= node->next) { if(node->flag & NODE_SELECT) { /* no groups in groups */ if(node->type==NODE_GROUP) return NULL; DO_MINMAX2( (&node->locx), min, max); totnode++; } node->done= 0; } if(totnode==0) return NULL; /* check if all connections are OK, no unselected node has both inputs and outputs to a selection */ for(link= ntree->links.first; link; link= link->next) { if(link->fromnode && link->tonode && link->fromnode->flag & NODE_SELECT) link->tonode->done |= 1; if(link->fromnode && link->tonode && link->tonode->flag & NODE_SELECT) link->fromnode->done |= 2; } for(node= ntree->nodes.first; node; node= node->next) { if((node->flag & NODE_SELECT)==0) if(node->done==3) break; } if(node) return NULL; /* OK! new nodetree */ ngroup= ntreeAddTree("NodeGroup", ntree->type, NODE_GROUP); /* move nodes over */ for(node= ntree->nodes.first; node; node= nextn) { nextn= node->next; if(node->flag & NODE_SELECT) { /* keep track of this node's RNA "base" path (the part of the pat identifying the node) * if the old nodetree has animation data which potentially covers this node */ if (ntree->adt) { PointerRNA ptr; char *path; RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr); path = RNA_path_from_ID_to_struct(&ptr); if (path) BLI_addtail(&anim_basepaths, BLI_genericNodeN(path)); } /* change node-collection membership */ BLI_remlink(&ntree->nodes, node); BLI_addtail(&ngroup->nodes, node); node->locx-= 0.5f*(min[0]+max[0]); node->locy-= 0.5f*(min[1]+max[1]); } } /* move animation data over */ if (ntree->adt) { LinkData *ld, *ldn=NULL; BKE_animdata_separate_by_basepath(&ntree->id, &ngroup->id, &anim_basepaths); /* paths + their wrappers need to be freed */ for (ld = anim_basepaths.first; ld; ld = ldn) { ldn = ld->next; MEM_freeN(ld->data); BLI_freelinkN(&anim_basepaths, ld); } } /* make group node */ ntemp.type = NODE_GROUP; ntemp.ngroup = ngroup; gnode= nodeAddNode(ntree, &ntemp); gnode->locx= 0.5f*(min[0]+max[0]); gnode->locy= 0.5f*(min[1]+max[1]); /* relink external sockets */ for(link= ntree->links.first; link; link= linkn) { linkn= link->next; if(link->fromnode && link->tonode && (link->fromnode->flag & link->tonode->flag & NODE_SELECT)) { BLI_remlink(&ntree->links, link); BLI_addtail(&ngroup->links, link); } else if(link->tonode && (link->tonode->flag & NODE_SELECT)) { gsock = node_group_expose_socket(ngroup, link->tosock, SOCK_IN); link->tosock->link = nodeAddLink(ngroup, NULL, gsock, link->tonode, link->tosock); link->tosock = node_group_add_extern_socket(ntree, &gnode->inputs, SOCK_IN, gsock); link->tonode = gnode; } else if(link->fromnode && (link->fromnode->flag & NODE_SELECT)) { /* search for existing group node socket */ for (gsock=ngroup->outputs.first; gsock; gsock=gsock->next) if (gsock->link && gsock->link->fromsock==link->fromsock) break; if (!gsock) { gsock = node_group_expose_socket(ngroup, link->fromsock, SOCK_OUT); gsock->link = nodeAddLink(ngroup, link->fromnode, link->fromsock, NULL, gsock); link->fromsock = node_group_add_extern_socket(ntree, &gnode->outputs, SOCK_OUT, gsock); } else link->fromsock = node_group_find_output(gnode, gsock); link->fromnode = gnode; } } ngroup->update |= NTREE_UPDATE; ntreeUpdateTree(ngroup); ntree->update |= NTREE_UPDATE_NODES|NTREE_UPDATE_LINKS; ntreeUpdateTree(ntree); return gnode; }
/* /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// */ static void get_material_startjob(void *customdata, short *stop, short *do_update, float *progress) { Main *bmain; bContext *C; bNodeTree *ntree; MatItem *items; uint32_t buf_size; GetMaterialJob *mj = customdata; mj->stop = stop; mj->do_update = do_update; mj->progress = progress; ntree = mj->ntree; bmain = mj->bmain; C = mj->C; *progress = 0.1f; items = mat_livedb_get_material(mj->address, mj->mat_id, &buf_size); *progress = 0.9f; if(items) { bNode *node, *next; MatItem *cur_item = items; bNode *node_to; bNodeSocket *sock_to; char file_path[FILE_MAX]; float cur_y_pos = 0; /* Remove all existing nodes */ ED_preview_kill_jobs(CTX_wm_manager(C), bmain); for (node = ntree->nodes.first; node; node = next) { next = node->next; /* check id user here, nodeFreeNode is called for free dbase too */ if (node->id) node->id->us--; nodeFreeNode(ntree, node); } ntreeUpdateTree(bmain, ntree); node_to = nodeAddNode(C, ntree, "ShaderNodeOutputMaterial"); node_to->locx = 0; node_to->locy = 0; for (sock_to = node_to->inputs.first; sock_to; sock_to = sock_to->next) { if(!sock_to || strcmp(sock_to->name, "Surface")) continue; break; } /* create file path */ if(!strlen(G.main->name)) { char *cur_path = (char*)BKE_appdir_folder_id_create(BLENDER_USER_DATAFILES, 0); strcpy(file_path, cur_path); strcat(file_path, "/livedb/"); } else { BLI_strncpy(file_path, "//livedb/", sizeof(file_path)); BLI_path_abs(file_path, G.main->name); } strcat(file_path, mj->address); strcat(file_path, "/textures/"); BLI_path_native_slash(file_path); BLI_dir_create_recursive(file_path); mat_livedb_add_mat_element(bmain, C, ntree, node_to, sock_to, &cur_item, file_path, 0, &cur_y_pos); ED_node_tree_update(C); ED_node_tag_update_nodetree(bmain, ntree, 0); MEM_freeN(items); } *do_update = 1; *stop = 0; *progress = 1.0f; return; } /* get_material_job() */
/* add new node connected to this socket, or replace an existing one */ static void node_socket_add_replace(Main *bmain, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to, bNodeTemplate *ntemp, int sock_num) { bNode *node_from; bNodeSocket *sock_from; bNode *node_prev = NULL; /* unlink existing node */ if (sock_to->link) { node_prev = sock_to->link->fromnode; nodeRemLink(ntree, sock_to->link); } /* find existing node that we can use */ for (node_from=ntree->nodes.first; node_from; node_from=node_from->next) if (node_from->type == ntemp->type) break; if (node_from) if (!(node_from->inputs.first == NULL && !(node_from->typeinfo->flag & NODE_OPTIONS))) node_from = NULL; if (node_prev && node_prev->type == ntemp->type && (ntemp->type != NODE_GROUP || node_prev->id == &ntemp->ngroup->id)) { /* keep the previous node if it's the same type */ node_from = node_prev; } else if (!node_from) { node_from= nodeAddNode(ntree, ntemp); node_from->locx = node_to->locx - (node_from->typeinfo->width + 50); node_from->locy = node_to->locy; if (node_from->id) id_us_plus(node_from->id); } nodeSetActive(ntree, node_from); /* add link */ sock_from = BLI_findlink(&node_from->outputs, sock_num); nodeAddLink(ntree, node_from, sock_from, node_to, sock_to); /* copy input sockets from previous node */ if (node_prev && node_from != node_prev) { bNodeSocket *sock_prev, *sock_from; for (sock_prev=node_prev->inputs.first; sock_prev; sock_prev=sock_prev->next) { for (sock_from=node_from->inputs.first; sock_from; sock_from=sock_from->next) { if (nodeCountSocketLinks(ntree, sock_from) >= sock_from->limit) continue; if (strcmp(sock_prev->name, sock_from->name) == 0 && sock_prev->type == sock_from->type) { bNodeLink *link = sock_prev->link; if (link && link->fromnode) { nodeAddLink(ntree, link->fromnode, link->fromsock, node_from, sock_from); nodeRemLink(ntree, link); } node_socket_free_default_value(sock_from->type, sock_from->default_value); sock_from->default_value = node_socket_make_default_value(sock_from->type); node_socket_copy_default_value(sock_from->type, sock_from->default_value, sock_prev->default_value); } } } /* also preserve mapping for texture nodes */ if (node_from->typeinfo->nclass == NODE_CLASS_TEXTURE && node_prev->typeinfo->nclass == NODE_CLASS_TEXTURE) { memcpy(node_from->storage, node_prev->storage, sizeof(NodeTexBase)); } /* remove node */ node_remove_linked(ntree, node_prev); } nodeUpdate(ntree, node_from); nodeUpdate(ntree, node_to); ntreeUpdateTree(ntree); ED_node_generic_update(bmain, ntree, node_to); }