test commit

This commit is contained in:
Joseph Eagar
2009-11-02 06:31:23 +00:00
parent 2d0d4e7de4
commit 71d2ceb691
4 changed files with 62 additions and 1286 deletions

View File

@@ -1989,67 +1989,74 @@ void CDDM_apply_vert_normals(DerivedMesh *dm, short (*vertNormals)[3])
VECCOPY(vert->no, vertNormals[i]);
}
/* adapted from mesh_calc_normals */
void CDDM_calc_normals(DerivedMesh *dm)
{
CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
float (*temp_nors)[3];
float (*face_nors)[3];
int i;
float (*vert_nors)[3];
int i, j, *origIndex;
int numVerts = dm->numVertData;
int numFaces = dm->numFaceData;
MFace *mf;
MPoly *mp;
MVert *mv;
MLoop *ml;
if(numVerts == 0) return;
temp_nors = MEM_callocN(numVerts * sizeof(*temp_nors),
"CDDM_calc_normals temp_nors");
if (CustomData_has_layer(&dm->faceData, CD_NORMAL))
CustomData_free_layer(&dm->faceData, CD_NORMAL, dm->numFaceData, 0);
/* we don't want to overwrite any referenced layers */
mv = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT);
cddm->mvert = mv;
/*recalc tesselation to ensure we have valid origindex values
for mface->mpoly lookups.*/
cdDM_recalcTesselation(dm);
/* make a face normal layer if not present */
face_nors = CustomData_get_layer(&dm->faceData, CD_NORMAL);
if(!face_nors)
face_nors = CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_CALLOC,
NULL, dm->numFaceData);
numFaces = dm->numFaceData;
/* calculate face normals and add to vertex normals */
mf = CDDM_get_tessfaces(dm);
for(i = 0; i < numFaces; i++, mf++) {
float *f_no = face_nors[i];
/*first go through and calculate normals for all the polys*/
temp_nors = MEM_callocN(sizeof(float)*3*dm->numPolyData, "temp_nors cdderivedmesh.c");
vert_nors = MEM_callocN(sizeof(float)*3*dm->numVertData, "vert_nors cdderivedmesh.c");
mp = cddm->mpoly;
for (i=0; i<dm->numPolyData; i++, mp++) {
mesh_calc_poly_normal(mp, cddm->mloop+mp->loopstart, cddm->mvert, temp_nors[i]);
if(mf->v4)
CalcNormFloat4(mv[mf->v1].co, mv[mf->v2].co,
mv[mf->v3].co, mv[mf->v4].co, f_no);
else
CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co,
mv[mf->v3].co, f_no);
VecAddf(temp_nors[mf->v1], temp_nors[mf->v1], f_no);
VecAddf(temp_nors[mf->v2], temp_nors[mf->v2], f_no);
VecAddf(temp_nors[mf->v3], temp_nors[mf->v3], f_no);
if(mf->v4)
VecAddf(temp_nors[mf->v4], temp_nors[mf->v4], f_no);
ml = cddm->mloop + mp->loopstart;
for (j=0; j<mp->totloop; j++, ml++) {
VECADD(vert_nors[ml->v], vert_nors[ml->v], temp_nors[i]);
}
}
/* normalize vertex normals and assign */
for(i = 0; i < numVerts; i++, mv++) {
float *no = temp_nors[i];
face_nors = MEM_callocN(sizeof(float)*3*dm->numFaceData, "face_nors cdderivedmesh.c");
CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_ASSIGN, face_nors, dm->numFaceData);
origIndex = CustomData_get_layer(&dm->faceData, CD_ORIGINDEX);
mf = cddm->mface;
for (i=0; i<dm->numFaceData; i++, mf++, origIndex++) {
VECCOPY(face_nors[i], temp_nors[*origIndex]);
}
mv = cddm->mvert;
for (i=0; i<dm->numVertData; i++, mv++) {
float *no = vert_nors[i];
if (Normalize(no) == 0.0) {
VECCOPY(no, mv->co);
Normalize(no);
if (Normalize(no) == 0.0) {
no[0] = 0.0f;
no[1] = 0.0f;
no[2] = 1.0f;
}
}
mv->no[0] = (short)(no[0] * 32767.0);
mv->no[1] = (short)(no[1] * 32767.0);
mv->no[2] = (short)(no[2] * 32767.0);
mv->no[0] = (short)(no[0] * 32767.0f);
mv->no[1] = (short)(no[1] * 32767.0f);
mv->no[2] = (short)(no[2] * 32767.0f);
}
MEM_freeN(temp_nors);
MEM_freeN(vert_nors);
}
void CDDM_calc_edges(DerivedMesh *dm)

View File

@@ -840,7 +840,6 @@ static void layerInterp_shapekey(void **sources, float *weights,
memset(co, 0, sizeof(float)*3);
sub_weight = sub_weights;
for(i = 0; i < count; ++i) {
float weight = weights ? weights[i] : 1.0f;
@@ -896,7 +895,7 @@ const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
{sizeof(MCol)*4, "MCol", 4, "TextureCol", NULL, NULL, layerInterp_mcol,
layerSwap_mcol, layerDefault_mcol},
{sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
{sizeof(float), "", 3, "ShapeKey", layerInterp_shapekey},
{sizeof(float)*3, "", 0, "ShapeKey", NULL, NULL, layerInterp_shapekey},
};
const char *LAYERTYPENAMES[CD_NUMTYPES] = {
@@ -904,7 +903,7 @@ const char *LAYERTYPENAMES[CD_NUMTYPES] = {
"CDMCol", "CDOrigIndex", "CDNormal", "CDFlags","CDMFloatProperty",
"CDMIntProperty","CDMStringProperty", "CDOrigSpace", "CDOrco", "CDMTexPoly", "CDMLoopUV",
"CDMloopCol", "CDTangent", "CDMDisps", "CDWeightMCol", "CDMPoly",
"CDMLoop", "CDMLoopCol", "CDIDCol", "CDTextureCol", "CDShapeKeyIndex"};
"CDMLoop", "CDMLoopCol", "CDIDCol", "CDTextureCol", "CDShapeKeyIndex", "CDShapeKey"};
const CustomDataMask CD_MASK_BAREMESH =
CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE | CD_MASK_MLOOP | CD_MASK_MPOLY;
@@ -913,7 +912,7 @@ const CustomDataMask CD_MASK_MESH =
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | CD_MASK_MCOL |
CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS |
CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MPOLY | CD_MASK_MLOOP |
CD_MASK_MTEXPOLY;
CD_MASK_MTEXPOLY | CD_MASK_NORMAL;
const CustomDataMask CD_MASK_EDITMESH =
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | CD_MASK_MLOOPUV |
CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_SHAPE_KEYINDEX |
@@ -923,7 +922,8 @@ const CustomDataMask CD_MASK_DERIVEDMESH =
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE |
CD_MASK_MCOL | CD_MASK_ORIGINDEX | CD_MASK_PROP_FLT | CD_MASK_PROP_INT |
CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_WEIGHT_MLOOPCOL |
CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_TANGENT | CD_MASK_WEIGHT_MCOL;
CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_TANGENT |
CD_MASK_WEIGHT_MCOL | CD_MASK_NORMAL;
const CustomDataMask CD_MASK_BMESH = CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY |
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT |
CD_MASK_PROP_STR | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX;
@@ -1075,6 +1075,17 @@ int CustomData_get_layer_index(const CustomData *data, int type)
return -1;
}
int CustomData_get_layer_index_n(const struct CustomData *data, int type, int n)
{
int i;
for(i=0; i < data->totlayer; ++i)
if(data->layers[i].type == type)
return i + n;
return -1;
}
int CustomData_get_named_layer_index(const CustomData *data, int type, char *name)
{
int i;

View File

@@ -118,6 +118,8 @@ Key *add_key(ID *id) /* common function */
key->type= KEY_NORMAL;
key->from= id;
key->uidgen = 1;
// XXX the code here uses some defines which will soon be depreceated...
if( GS(id->name)==ID_ME) {

View File

@@ -1927,1248 +1927,4 @@ static void composit_begin_exec(bNodeTree *ntree, int is_group)
bNode *node;
bNodeSocket *sock;
for(node= ntree->nodes.first; node; node= node->next) {
/* initialize needed for groups */
node->exec= 0;
if(is_group==0) {
for(sock= node->outputs.first; sock; sock= sock->next) {
bNodeStack *ns= ntree->stack + sock->stack_index;
if(sock->ns.data) {
ns->data= sock->ns.data;
sock->ns.data= NULL;
}
}
}
/* cannot initialize them while using in threads */
if(ELEM3(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB)) {
curvemapping_initialize(node->storage);
if(node->type==CMP_NODE_CURVE_RGB)
curvemapping_premultiply(node->storage, 0);
}
if(node->type==NODE_GROUP)
composit_begin_exec((bNodeTree *)node->id, 1);
}
}
/* copy stack compbufs to sockets */
static void composit_end_exec(bNodeTree *ntree, int is_group)
{
extern void print_compbuf(char *str, struct CompBuf *cbuf);
bNode *node;
bNodeStack *ns;
int a;
for(node= ntree->nodes.first; node; node= node->next) {
if(is_group==0) {
bNodeSocket *sock;
for(sock= node->outputs.first; sock; sock= sock->next) {
ns= ntree->stack + sock->stack_index;
if(ns->data) {
sock->ns.data= ns->data;
ns->data= NULL;
}
}
}
if(node->type==CMP_NODE_CURVE_RGB)
curvemapping_premultiply(node->storage, 1);
if(node->type==NODE_GROUP)
composit_end_exec((bNodeTree *)node->id, 1);
node->need_exec= 0;
}
if(is_group==0) {
/* internally, group buffers are not stored */
for(ns= ntree->stack, a=0; a<ntree->stacksize; a++, ns++) {
if(ns->data) {
printf("freed leftover buffer from stack\n");
free_compbuf(ns->data);
ns->data= NULL;
}
}
}
}
static void group_tag_used_outputs(bNode *gnode, bNodeStack *stack)
{
bNodeTree *ntree= (bNodeTree *)gnode->id;
bNode *node;
stack+= gnode->stack_index;
for(node= ntree->nodes.first; node; node= node->next) {
if(node->typeinfo->execfunc) {
bNodeSocket *sock;
for(sock= node->inputs.first; sock; sock= sock->next) {
if(sock->intern) {
if(sock->link) {
bNodeStack *ns= stack + sock->link->fromsock->stack_index;
ns->hasoutput= 1;
ns->sockettype= sock->link->fromsock->type;
}
else
sock->ns.sockettype= sock->type;
}
}
}
}
}
/* notes below are ancient! (ton) */
/* stack indices make sure all nodes only write in allocated data, for making it thread safe */
/* only root tree gets the stack, to enable instances to have own stack entries */
/* per tree (and per group) unique indices are created */
/* the index_ext we need to be able to map from groups to the group-node own stack */
typedef struct bNodeThreadStack {
struct bNodeThreadStack *next, *prev;
bNodeStack *stack;
int used;
} bNodeThreadStack;
static bNodeThreadStack *ntreeGetThreadStack(bNodeTree *ntree, int thread)
{
ListBase *lb= &ntree->threadstack[thread];
bNodeThreadStack *nts;
for(nts=lb->first; nts; nts=nts->next) {
if(!nts->used) {
nts->used= 1;
return nts;
}
}
nts= MEM_callocN(sizeof(bNodeThreadStack), "bNodeThreadStack");
nts->stack= MEM_dupallocN(ntree->stack);
nts->used= 1;
BLI_addtail(lb, nts);
return nts;
}
static void ntreeReleaseThreadStack(bNodeThreadStack *nts)
{
nts->used= 0;
}
/* free texture delegates */
static void tex_end_exec(bNodeTree *ntree)
{
bNodeThreadStack *nts;
bNodeStack *ns;
int th, a;
if(ntree->threadstack)
for(th=0; th<BLENDER_MAX_THREADS; th++)
for(nts=ntree->threadstack[th].first; nts; nts=nts->next)
for(ns= nts->stack, a=0; a<ntree->stacksize; a++, ns++)
if(ns->data)
MEM_freeN(ns->data);
}
void ntreeBeginExecTree(bNodeTree *ntree)
{
/* let's make it sure */
if(ntree->init & NTREE_EXEC_INIT)
return;
/* allocate the thread stack listbase array */
if(ntree->type!=NTREE_COMPOSIT)
ntree->threadstack= MEM_callocN(BLENDER_MAX_THREADS*sizeof(ListBase), "thread stack array");
/* goes recursive over all groups */
ntree->stacksize= ntree_begin_exec_tree(ntree);
if(ntree->stacksize) {
bNode *node;
bNodeStack *ns;
int a;
/* allocate the base stack */
ns=ntree->stack= MEM_callocN(ntree->stacksize*sizeof(bNodeStack), "node stack");
/* tag inputs, the get_stack() gives own socket stackdata if not in use */
for(a=0; a<ntree->stacksize; a++, ns++) ns->hasinput= 1;
/* tag used outputs, so we know when we can skip operations */
for(node= ntree->nodes.first; node; node= node->next) {
bNodeSocket *sock;
/* composite has own need_exec tag handling */
if(ntree->type!=NTREE_COMPOSIT)
node->need_exec= 1;
for(sock= node->inputs.first; sock; sock= sock->next) {
if(sock->link) {
ns= ntree->stack + sock->link->fromsock->stack_index;
ns->hasoutput= 1;
ns->sockettype= sock->link->fromsock->type;
}
else
sock->ns.sockettype= sock->type;
if(sock->link) {
bNodeLink *link= sock->link;
/* this is the test for a cyclic case */
if(link->fromnode && link->tonode) {
if(link->fromnode->level >= link->tonode->level && link->tonode->level!=0xFFF);
else {
node->need_exec= 0;
}
}
}
}
if(node->type==NODE_GROUP && node->id)
group_tag_used_outputs(node, ntree->stack);
}
if(ntree->type==NTREE_COMPOSIT)
composit_begin_exec(ntree, 0);
}
ntree->init |= NTREE_EXEC_INIT;
}
void ntreeEndExecTree(bNodeTree *ntree)
{
if(ntree->init & NTREE_EXEC_INIT) {
bNodeThreadStack *nts;
int a;
/* another callback candidate! */
if(ntree->type==NTREE_COMPOSIT)
composit_end_exec(ntree, 0);
else if(ntree->type==NTREE_TEXTURE)
tex_end_exec(ntree);
if(ntree->stack) {
MEM_freeN(ntree->stack);
ntree->stack= NULL;
}
if(ntree->threadstack) {
for(a=0; a<BLENDER_MAX_THREADS; a++) {
for(nts=ntree->threadstack[a].first; nts; nts=nts->next)
if (nts->stack) MEM_freeN(nts->stack);
BLI_freelistN(&ntree->threadstack[a]);
}
MEM_freeN(ntree->threadstack);
ntree->threadstack= NULL;
}
ntree->init &= ~NTREE_EXEC_INIT;
}
}
static void node_get_stack(bNode *node, bNodeStack *stack, bNodeStack **in, bNodeStack **out)
{
bNodeSocket *sock;
/* build pointer stack */
for(sock= node->inputs.first; sock; sock= sock->next) {
if(sock->link)
*(in++)= stack + sock->link->fromsock->stack_index;
else
*(in++)= &sock->ns;
}
for(sock= node->outputs.first; sock; sock= sock->next) {
*(out++)= stack + sock->stack_index;
}
}
/* nodes are presorted, so exec is in order of list */
void ntreeExecTree(bNodeTree *ntree, void *callerdata, int thread)
{
bNode *node;
bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */
bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */
bNodeStack *stack;
bNodeThreadStack *nts = NULL;
/* only when initialized */
if((ntree->init & NTREE_EXEC_INIT)==0)
ntreeBeginExecTree(ntree);
/* composite does 1 node per thread, so no multiple stacks needed */
if(ntree->type==NTREE_COMPOSIT) {
stack= ntree->stack;
}
else {
nts= ntreeGetThreadStack(ntree, thread);
stack= nts->stack;
}
for(node= ntree->nodes.first; node; node= node->next) {
if(node->need_exec) {
if(node->typeinfo->execfunc) {
node_get_stack(node, stack, nsin, nsout);
node->typeinfo->execfunc(callerdata, node, nsin, nsout);
}
else if(node->type==NODE_GROUP && node->id) {
node_get_stack(node, stack, nsin, nsout);
node_group_execute(stack, callerdata, node, nsin, nsout);
}
}
}
if(nts)
ntreeReleaseThreadStack(nts);
}
/* ***************************** threaded version for execute composite nodes ************* */
/* these are nodes without input, only giving values */
/* or nodes with only value inputs */
static int node_only_value(bNode *node)
{
bNodeSocket *sock;
if(ELEM3(node->type, CMP_NODE_TIME, CMP_NODE_VALUE, CMP_NODE_RGB))
return 1;
/* doing this for all node types goes wrong. memory free errors */
if(node->inputs.first && node->type==CMP_NODE_MAP_VALUE) {
int retval= 1;
for(sock= node->inputs.first; sock; sock= sock->next) {
if(sock->link)
retval &= node_only_value(sock->link->fromnode);
}
return retval;
}
return 0;
}
/* not changing info, for thread callback */
typedef struct ThreadData {
bNodeStack *stack;
RenderData *rd;
} ThreadData;
static void *exec_composite_node(void *node_v)
{
bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */
bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */
bNode *node= node_v;
ThreadData *thd= (ThreadData *)node->threaddata;
node_get_stack(node, thd->stack, nsin, nsout);
if((node->flag & NODE_MUTED) && (!node_only_value(node))) {
/* viewers we execute, for feedback to user */
if(ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
node->typeinfo->execfunc(thd->rd, node, nsin, nsout);
else
node_compo_pass_on(node, nsin, nsout);
}
else if(node->typeinfo->execfunc) {
node->typeinfo->execfunc(thd->rd, node, nsin, nsout);
}
else if(node->type==NODE_GROUP && node->id) {
node_group_execute(thd->stack, thd->rd, node, nsin, nsout);
}
node->exec |= NODE_READY;
return 0;
}
/* return total of executable nodes, for timecursor */
/* only compositor uses it */
static int setExecutableNodes(bNodeTree *ntree, ThreadData *thd)
{
bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */
bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */
bNode *node;
bNodeSocket *sock;
int totnode= 0, group_edit= 0;
/* note; do not add a dependency sort here, the stack was created already */
/* if we are in group edit, viewer nodes get skipped when group has viewer */
for(node= ntree->nodes.first; node; node= node->next)
if(node->type==NODE_GROUP && (node->flag & NODE_GROUP_EDIT))
if(ntreeHasType((bNodeTree *)node->id, CMP_NODE_VIEWER))
group_edit= 1;
for(node= ntree->nodes.first; node; node= node->next) {
int a;
node_get_stack(node, thd->stack, nsin, nsout);
/* test the outputs */
/* skip value-only nodes (should be in type!) */
if(!node_only_value(node)) {
for(a=0, sock= node->outputs.first; sock; sock= sock->next, a++) {
if(nsout[a]->data==NULL && nsout[a]->hasoutput) {
node->need_exec= 1;
break;
}
}
}
/* test the inputs */
for(a=0, sock= node->inputs.first; sock; sock= sock->next, a++) {
/* skip viewer nodes in bg render or group edit */
if( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER) && (G.background || group_edit))
node->need_exec= 0;
/* is sock in use? */
else if(sock->link) {
bNodeLink *link= sock->link;
/* this is the test for a cyclic case */
if(link->fromnode==NULL || link->tonode==NULL);
else if(link->fromnode->level >= link->tonode->level && link->tonode->level!=0xFFF) {
if(link->fromnode->need_exec) {
node->need_exec= 1;
break;
}
}
else {
node->need_exec= 0;
printf("Node %s skipped, cyclic dependency\n", node->name);
}
}
}
if(node->need_exec) {
/* free output buffers */
for(a=0, sock= node->outputs.first; sock; sock= sock->next, a++) {
if(nsout[a]->data) {
free_compbuf(nsout[a]->data);
nsout[a]->data= NULL;
}
}
totnode++;
/* printf("node needs exec %s\n", node->name); */
/* tag for getExecutableNode() */
node->exec= 0;
}
else {
/* tag for getExecutableNode() */
node->exec= NODE_READY|NODE_FINISHED|NODE_SKIPPED;
}
}
/* last step: set the stack values for only-value nodes */
/* just does all now, compared to a full buffer exec this is nothing */
if(totnode) {
for(node= ntree->nodes.first; node; node= node->next) {
if(node->need_exec==0 && node_only_value(node)) {
if(node->typeinfo->execfunc) {
node_get_stack(node, thd->stack, nsin, nsout);
node->typeinfo->execfunc(thd->rd, node, nsin, nsout);
}
}
}
}
return totnode;
}
/* while executing tree, free buffers from nodes that are not needed anymore */
static void freeExecutableNode(bNodeTree *ntree)
{
/* node outputs can be freed when:
- not a render result or image node
- when node outputs go to nodes all being set NODE_FINISHED
*/
bNode *node;
bNodeSocket *sock;
/* set exec flag for finished nodes that might need freed */
for(node= ntree->nodes.first; node; node= node->next) {
if(node->type!=CMP_NODE_R_LAYERS)
if(node->exec & NODE_FINISHED)
node->exec |= NODE_FREEBUFS;
}
/* clear this flag for input links that are not done yet */
for(node= ntree->nodes.first; node; node= node->next) {
if((node->exec & NODE_FINISHED)==0) {
for(sock= node->inputs.first; sock; sock= sock->next)
if(sock->link)
sock->link->fromnode->exec &= ~NODE_FREEBUFS;
}
}
/* now we can free buffers */
for(node= ntree->nodes.first; node; node= node->next) {
if(node->exec & NODE_FREEBUFS) {
for(sock= node->outputs.first; sock; sock= sock->next) {
bNodeStack *ns= ntree->stack + sock->stack_index;
if(ns->data) {
free_compbuf(ns->data);
ns->data= NULL;
// printf("freed buf node %s \n", node->name);
}
}
}
}
}
static bNode *getExecutableNode(bNodeTree *ntree)
{
bNode *node;
bNodeSocket *sock;
for(node= ntree->nodes.first; node; node= node->next) {
if(node->exec==0) {
/* input sockets should be ready */
for(sock= node->inputs.first; sock; sock= sock->next) {
if(sock->link)
if((sock->link->fromnode->exec & NODE_READY)==0)
break;
}
if(sock==NULL)
return node;
}
}
return NULL;
}
/* optimized tree execute test for compositing */
void ntreeCompositExecTree(bNodeTree *ntree, RenderData *rd, int do_preview)
{
bNode *node;
ListBase threads;
ThreadData thdata;
int totnode, rendering= 1;
if(ntree==NULL) return;
if(do_preview)
ntreeInitPreview(ntree, 0, 0);
ntreeBeginExecTree(ntree);
/* prevent unlucky accidents */
if(G.background)
rd->scemode &= ~R_COMP_CROP;
/* setup callerdata for thread callback */
thdata.rd= rd;
thdata.stack= ntree->stack;
/* fixed seed, for example noise texture */
BLI_srandom(rd->cfra);
/* sets need_exec tags in nodes */
totnode= setExecutableNodes(ntree, &thdata);
BLI_init_threads(&threads, exec_composite_node, rd->threads);
while(rendering) {
if(BLI_available_threads(&threads)) {
node= getExecutableNode(ntree);
if(node) {
if(ntree->timecursor)
ntree->timecursor(ntree->tch, totnode);
if(ntree->stats_draw) {
char str[64];
sprintf(str, "Compositing %d %s", totnode, node->name);
ntree->stats_draw(ntree->sdh, str);
}
totnode--;
node->threaddata = &thdata;
node->exec= NODE_PROCESSING;
BLI_insert_thread(&threads, node);
}
else
PIL_sleep_ms(50);
}
else
PIL_sleep_ms(50);
rendering= 0;
/* test for ESC */
if(ntree->test_break && ntree->test_break(ntree->tbh)) {
for(node= ntree->nodes.first; node; node= node->next)
node->exec |= NODE_READY;
}
/* check for ready ones, and if we need to continue */
for(node= ntree->nodes.first; node; node= node->next) {
if(node->exec & NODE_READY) {
if((node->exec & NODE_FINISHED)==0) {
BLI_remove_thread(&threads, node); /* this waits for running thread to finish btw */
node->exec |= NODE_FINISHED;
/* freeing unused buffers */
if(rd->scemode & R_COMP_FREE)
freeExecutableNode(ntree);
}
}
else rendering= 1;
}
}
BLI_end_threads(&threads);
ntreeEndExecTree(ntree);
}
/* ********** copy composite tree entirely, to allow threaded exec ******************* */
/* ***************** do NOT execute this in a thread! ****************** */
/* returns localized composite tree for execution in threads */
/* local tree then owns all compbufs */
bNodeTree *ntreeLocalize(bNodeTree *ntree)
{
bNodeTree *ltree= ntreeCopyTree(ntree, 0);
bNode *node;
bNodeSocket *sock;
/* move over the compbufs */
/* right after ntreeCopyTree() oldsock pointers are valid */
for(node= ntree->nodes.first; node; node= node->next) {
/* store new_node pointer to original */
node->new_node->new_node= node;
/* ensure new user input gets handled ok */
node->need_exec= 0;
if(ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
if(node->id) {
if(node->flag & NODE_DO_OUTPUT)
node->new_node->id= (ID *)BKE_image_copy((Image *)node->id);
else
node->new_node->id= NULL;
}
}
for(sock= node->outputs.first; sock; sock= sock->next) {
sock->new_sock->ns.data= sock->ns.data;
sock->ns.data= NULL;
sock->new_sock->new_sock= sock;
}
}
return ltree;
}
static int node_exists(bNodeTree *ntree, bNode *testnode)
{
bNode *node= ntree->nodes.first;
for(; node; node= node->next)
if(node==testnode)
return 1;
return 0;
}
static int outsocket_exists(bNode *node, bNodeSocket *testsock)
{
bNodeSocket *sock= node->outputs.first;
for(; sock; sock= sock->next)
if(sock==testsock)
return 1;
return 0;
}
/* sync local composite with real tree */
/* local composite is supposed to be running, be careful moving previews! */
void ntreeLocalSync(bNodeTree *localtree, bNodeTree *ntree)
{
bNode *lnode;
/* move over the compbufs and previews */
for(lnode= localtree->nodes.first; lnode; lnode= lnode->next) {
if( (lnode->exec & NODE_READY) && !(lnode->exec & NODE_SKIPPED) ) {
if(node_exists(ntree, lnode->new_node)) {
if(lnode->preview && lnode->preview->rect) {
node_free_preview(lnode->new_node);
lnode->new_node->preview= lnode->preview;
lnode->preview= NULL;
}
}
}
}
}
/* merge local tree results back, and free local tree */
/* we have to assume the editor already changed completely */
void ntreeLocalMerge(bNodeTree *localtree, bNodeTree *ntree)
{
bNode *lnode;
bNodeSocket *lsock;
/* move over the compbufs and previews */
for(lnode= localtree->nodes.first; lnode; lnode= lnode->next) {
if(node_exists(ntree, lnode->new_node)) {
if(lnode->preview && lnode->preview->rect) {
node_free_preview(lnode->new_node);
lnode->new_node->preview= lnode->preview;
lnode->preview= NULL;
}
if(ELEM(lnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
if(lnode->id && (lnode->flag & NODE_DO_OUTPUT)) {
/* image_merge does sanity check for pointers */
BKE_image_merge((Image *)lnode->new_node->id, (Image *)lnode->id);
}
}
for(lsock= lnode->outputs.first; lsock; lsock= lsock->next) {
if(outsocket_exists(lnode->new_node, lsock->new_sock)) {
lsock->new_sock->ns.data= lsock->ns.data;
lsock->ns.data= NULL;
lsock->new_sock= NULL;
}
}
}
}
ntreeFreeTree(localtree);
MEM_freeN(localtree);
}
/* *********************************************** */
/* GPU material from shader nodes */
static void gpu_from_node_stack(ListBase *sockets, bNodeStack **ns, GPUNodeStack *gs)
{
bNodeSocket *sock;
int i;
for (sock=sockets->first, i=0; sock; sock=sock->next, i++) {
memset(&gs[i], 0, sizeof(gs[i]));
QUATCOPY(gs[i].vec, ns[i]->vec);
gs[i].link= ns[i]->data;
if (sock->type == SOCK_VALUE)
gs[i].type= GPU_FLOAT;
else if (sock->type == SOCK_VECTOR)
gs[i].type= GPU_VEC3;
else if (sock->type == SOCK_RGBA)
gs[i].type= GPU_VEC4;
else
gs[i].type= GPU_NONE;
gs[i].name = "";
gs[i].hasinput= ns[i]->hasinput && ns[i]->data;
gs[i].hasoutput= ns[i]->hasinput && ns[i]->data;
gs[i].sockettype= ns[i]->sockettype;
}
gs[i].type= GPU_NONE;
}
static void data_from_gpu_stack(ListBase *sockets, bNodeStack **ns, GPUNodeStack *gs)
{
bNodeSocket *sock;
int i;
for (sock=sockets->first, i=0; sock; sock=sock->next, i++) {
ns[i]->data= gs[i].link;
ns[i]->hasinput= gs[i].hasinput && gs[i].link;
ns[i]->hasoutput= gs[i].hasoutput;
ns[i]->sockettype= gs[i].sockettype;
}
}
static void gpu_node_group_execute(bNodeStack *stack, GPUMaterial *mat, bNode *gnode, bNodeStack **in, bNodeStack **out)
{
bNode *node;
bNodeTree *ntree= (bNodeTree *)gnode->id;
bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */
bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */
GPUNodeStack gpuin[MAX_SOCKET+1], gpuout[MAX_SOCKET+1];
int doit = 0;
if(ntree==NULL) return;
stack+= gnode->stack_index;
for(node= ntree->nodes.first; node; node= node->next) {
if(node->typeinfo->gpufunc) {
group_node_get_stack(node, stack, nsin, nsout, in, out);
doit = 0;
/* for groups, only execute outputs for edited group */
if(node->typeinfo->nclass==NODE_CLASS_OUTPUT) {
if(gnode->flag & NODE_GROUP_EDIT)
if(node->flag & NODE_DO_OUTPUT)
doit = 1;
}
else
doit = 1;
if(doit) {
gpu_from_node_stack(&node->inputs, nsin, gpuin);
gpu_from_node_stack(&node->outputs, nsout, gpuout);
if(node->typeinfo->gpufunc(mat, node, gpuin, gpuout))
data_from_gpu_stack(&node->outputs, nsout, gpuout);
}
}
}
}
void ntreeGPUMaterialNodes(bNodeTree *ntree, GPUMaterial *mat)
{
bNode *node;
bNodeStack *stack;
bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */
bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */
GPUNodeStack gpuin[MAX_SOCKET+1], gpuout[MAX_SOCKET+1];
if((ntree->init & NTREE_EXEC_INIT)==0)
ntreeBeginExecTree(ntree);
stack= ntree->stack;
for(node= ntree->nodes.first; node; node= node->next) {
if(node->typeinfo->gpufunc) {
node_get_stack(node, stack, nsin, nsout);
gpu_from_node_stack(&node->inputs, nsin, gpuin);
gpu_from_node_stack(&node->outputs, nsout, gpuout);
if(node->typeinfo->gpufunc(mat, node, gpuin, gpuout))
data_from_gpu_stack(&node->outputs, nsout, gpuout);
}
else if(node->type==NODE_GROUP && node->id) {
node_get_stack(node, stack, nsin, nsout);
gpu_node_group_execute(stack, mat, node, nsin, nsout);
}
}
ntreeEndExecTree(ntree);
}
/* **************** call to switch lamploop for material node ************ */
void (*node_shader_lamp_loop)(struct ShadeInput *, struct ShadeResult *);
void set_node_shader_lamp_loop(void (*lamp_loop_func)(ShadeInput *, ShadeResult *))
{
node_shader_lamp_loop= lamp_loop_func;
}
/* clumsy checking... should do dynamic outputs once */
static void force_hidden_passes(bNode *node, int passflag)
{
bNodeSocket *sock;
for(sock= node->outputs.first; sock; sock= sock->next)
sock->flag &= ~SOCK_UNAVAIL;
sock= BLI_findlink(&node->outputs, RRES_OUT_Z);
if(!(passflag & SCE_PASS_Z)) sock->flag |= SOCK_UNAVAIL;
sock= BLI_findlink(&node->outputs, RRES_OUT_NORMAL);
if(!(passflag & SCE_PASS_NORMAL)) sock->flag |= SOCK_UNAVAIL;
sock= BLI_findlink(&node->outputs, RRES_OUT_VEC);
if(!(passflag & SCE_PASS_VECTOR)) sock->flag |= SOCK_UNAVAIL;
sock= BLI_findlink(&node->outputs, RRES_OUT_UV);
if(!(passflag & SCE_PASS_UV)) sock->flag |= SOCK_UNAVAIL;
sock= BLI_findlink(&node->outputs, RRES_OUT_RGBA);
if(!(passflag & SCE_PASS_RGBA)) sock->flag |= SOCK_UNAVAIL;
sock= BLI_findlink(&node->outputs, RRES_OUT_DIFF);
if(!(passflag & SCE_PASS_DIFFUSE)) sock->flag |= SOCK_UNAVAIL;
sock= BLI_findlink(&node->outputs, RRES_OUT_SPEC);
if(!(passflag & SCE_PASS_SPEC)) sock->flag |= SOCK_UNAVAIL;
sock= BLI_findlink(&node->outputs, RRES_OUT_SHADOW);
if(!(passflag & SCE_PASS_SHADOW)) sock->flag |= SOCK_UNAVAIL;
sock= BLI_findlink(&node->outputs, RRES_OUT_AO);
if(!(passflag & SCE_PASS_AO)) sock->flag |= SOCK_UNAVAIL;
sock= BLI_findlink(&node->outputs, RRES_OUT_REFLECT);
if(!(passflag & SCE_PASS_REFLECT)) sock->flag |= SOCK_UNAVAIL;
sock= BLI_findlink(&node->outputs, RRES_OUT_REFRACT);
if(!(passflag & SCE_PASS_REFRACT)) sock->flag |= SOCK_UNAVAIL;
sock= BLI_findlink(&node->outputs, RRES_OUT_RADIO);
if(!(passflag & SCE_PASS_RADIO)) sock->flag |= SOCK_UNAVAIL;
sock= BLI_findlink(&node->outputs, RRES_OUT_INDEXOB);
if(!(passflag & SCE_PASS_INDEXOB)) sock->flag |= SOCK_UNAVAIL;
sock= BLI_findlink(&node->outputs, RRES_OUT_MIST);
if(!(passflag & SCE_PASS_MIST)) sock->flag |= SOCK_UNAVAIL;
}
/* based on rules, force sockets hidden always */
void ntreeCompositForceHidden(bNodeTree *ntree, Scene *curscene)
{
bNode *node;
if(ntree==NULL) return;
for(node= ntree->nodes.first; node; node= node->next) {
if( node->type==CMP_NODE_R_LAYERS) {
Scene *sce= node->id?(Scene *)node->id:curscene;
SceneRenderLayer *srl= BLI_findlink(&sce->r.layers, node->custom1);
if(srl)
force_hidden_passes(node, srl->passflag);
}
else if( node->type==CMP_NODE_IMAGE) {
Image *ima= (Image *)node->id;
if(ima) {
if(ima->rr) {
ImageUser *iuser= node->storage;
RenderLayer *rl= BLI_findlink(&ima->rr->layers, iuser->layer);
if(rl)
force_hidden_passes(node, rl->passflag);
else
force_hidden_passes(node, 0);
}
else if(ima->type!=IMA_TYPE_MULTILAYER) { /* if ->rr not yet read we keep inputs */
force_hidden_passes(node, RRES_OUT_Z);
}
else
force_hidden_passes(node, 0);
}
else
force_hidden_passes(node, 0);
}
}
}
/* called from render pipeline, to tag render input and output */
/* need to do all scenes, to prevent errors when you re-render 1 scene */
void ntreeCompositTagRender(Scene *curscene)
{
Scene *sce;
for(sce= G.main->scene.first; sce; sce= sce->id.next) {
if(sce->nodetree) {
bNode *node;
for(node= sce->nodetree->nodes.first; node; node= node->next) {
if(node->id==(ID *)curscene || node->type==CMP_NODE_COMPOSITE)
NodeTagChanged(sce->nodetree, node);
}
}
}
}
/* tags nodes that have animation capabilities */
int ntreeCompositTagAnimated(bNodeTree *ntree)
{
bNode *node;
int tagged= 0;
if(ntree==NULL) return 0;
for(node= ntree->nodes.first; node; node= node->next) {
if(node->type==CMP_NODE_IMAGE) {
Image *ima= (Image *)node->id;
if(ima && ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
NodeTagChanged(ntree, node);
tagged= 1;
}
}
else if(node->type==CMP_NODE_TIME) {
NodeTagChanged(ntree, node);
tagged= 1;
}
else if(node->type==CMP_NODE_R_LAYERS) {
NodeTagChanged(ntree, node);
tagged= 1;
}
else if(node->type==NODE_GROUP) {
if( ntreeCompositTagAnimated((bNodeTree *)node->id) ) {
NodeTagChanged(ntree, node);
}
}
}
return tagged;
}
/* called from image window preview */
void ntreeCompositTagGenerators(bNodeTree *ntree)
{
bNode *node;
if(ntree==NULL) return;
for(node= ntree->nodes.first; node; node= node->next) {
if( ELEM(node->type, CMP_NODE_R_LAYERS, CMP_NODE_IMAGE))
NodeTagChanged(ntree, node);
}
}
int ntreeTexTagAnimated(bNodeTree *ntree)
{
bNode *node;
if(ntree==NULL) return 0;
for(node= ntree->nodes.first; node; node= node->next) {
if(node->type==TEX_NODE_CURVE_TIME) {
NodeTagChanged(ntree, node);
return 1;
}
else if(node->type==NODE_GROUP) {
if( ntreeTexTagAnimated((bNodeTree *)node->id) ) {
return 1;
}
}
}
return 0;
}
/* ************* node definition init ********** */
static bNodeType *is_nodetype_registered(ListBase *typelist, int type, ID *id)
{
bNodeType *ntype= typelist->first;
for(;ntype; ntype= ntype->next )
if(ntype->type==type && ntype->id==id)
return ntype;
return NULL;
}
/* type can be from a static array, we make copy for duplicate types (like group) */
void nodeRegisterType(ListBase *typelist, const bNodeType *ntype)
{
bNodeType *found= is_nodetype_registered(typelist, ntype->type, ntype->id);
if(found==NULL) {
bNodeType *ntypen= MEM_callocN(sizeof(bNodeType), "node type");
*ntypen= *ntype;
BLI_addtail(typelist, ntypen);
}
}
static void registerCompositNodes(ListBase *ntypelist)
{
nodeRegisterType(ntypelist, &node_group_typeinfo);
nodeRegisterType(ntypelist, &cmp_node_rlayers);
nodeRegisterType(ntypelist, &cmp_node_image);
nodeRegisterType(ntypelist, &cmp_node_texture);
nodeRegisterType(ntypelist, &cmp_node_value);
nodeRegisterType(ntypelist, &cmp_node_rgb);
nodeRegisterType(ntypelist, &cmp_node_curve_time);
nodeRegisterType(ntypelist, &cmp_node_composite);
nodeRegisterType(ntypelist, &cmp_node_viewer);
nodeRegisterType(ntypelist, &cmp_node_splitviewer);
nodeRegisterType(ntypelist, &cmp_node_output_file);
nodeRegisterType(ntypelist, &cmp_node_view_levels);
nodeRegisterType(ntypelist, &cmp_node_curve_rgb);
nodeRegisterType(ntypelist, &cmp_node_mix_rgb);
nodeRegisterType(ntypelist, &cmp_node_hue_sat);
nodeRegisterType(ntypelist, &cmp_node_brightcontrast);
nodeRegisterType(ntypelist, &cmp_node_gamma);
nodeRegisterType(ntypelist, &cmp_node_invert);
nodeRegisterType(ntypelist, &cmp_node_alphaover);
nodeRegisterType(ntypelist, &cmp_node_zcombine);
nodeRegisterType(ntypelist, &cmp_node_normal);
nodeRegisterType(ntypelist, &cmp_node_curve_vec);
nodeRegisterType(ntypelist, &cmp_node_map_value);
nodeRegisterType(ntypelist, &cmp_node_normalize);
nodeRegisterType(ntypelist, &cmp_node_filter);
nodeRegisterType(ntypelist, &cmp_node_blur);
nodeRegisterType(ntypelist, &cmp_node_dblur);
nodeRegisterType(ntypelist, &cmp_node_bilateralblur);
nodeRegisterType(ntypelist, &cmp_node_vecblur);
nodeRegisterType(ntypelist, &cmp_node_dilateerode);
nodeRegisterType(ntypelist, &cmp_node_defocus);
nodeRegisterType(ntypelist, &cmp_node_valtorgb);
nodeRegisterType(ntypelist, &cmp_node_rgbtobw);
nodeRegisterType(ntypelist, &cmp_node_setalpha);
nodeRegisterType(ntypelist, &cmp_node_idmask);
nodeRegisterType(ntypelist, &cmp_node_math);
nodeRegisterType(ntypelist, &cmp_node_seprgba);
nodeRegisterType(ntypelist, &cmp_node_combrgba);
nodeRegisterType(ntypelist, &cmp_node_sephsva);
nodeRegisterType(ntypelist, &cmp_node_combhsva);
nodeRegisterType(ntypelist, &cmp_node_sepyuva);
nodeRegisterType(ntypelist, &cmp_node_combyuva);
nodeRegisterType(ntypelist, &cmp_node_sepycca);
nodeRegisterType(ntypelist, &cmp_node_combycca);
nodeRegisterType(ntypelist, &cmp_node_premulkey);
nodeRegisterType(ntypelist, &cmp_node_diff_matte);
nodeRegisterType(ntypelist, &cmp_node_distance_matte);
nodeRegisterType(ntypelist, &cmp_node_chroma_matte);
nodeRegisterType(ntypelist, &cmp_node_color_matte);
nodeRegisterType(ntypelist, &cmp_node_channel_matte);
nodeRegisterType(ntypelist, &cmp_node_color_spill);
nodeRegisterType(ntypelist, &cmp_node_luma_matte);
nodeRegisterType(ntypelist, &cmp_node_translate);
nodeRegisterType(ntypelist, &cmp_node_rotate);
nodeRegisterType(ntypelist, &cmp_node_scale);
nodeRegisterType(ntypelist, &cmp_node_flip);
nodeRegisterType(ntypelist, &cmp_node_crop);
nodeRegisterType(ntypelist, &cmp_node_displace);
nodeRegisterType(ntypelist, &cmp_node_mapuv);
nodeRegisterType(ntypelist, &cmp_node_glare);
nodeRegisterType(ntypelist, &cmp_node_tonemap);
nodeRegisterType(ntypelist, &cmp_node_lensdist);
}
static void registerShaderNodes(ListBase *ntypelist)
{
nodeRegisterType(ntypelist, &node_group_typeinfo);
nodeRegisterType(ntypelist, &sh_node_output);
nodeRegisterType(ntypelist, &sh_node_mix_rgb);
nodeRegisterType(ntypelist, &sh_node_valtorgb);
nodeRegisterType(ntypelist, &sh_node_rgbtobw);
nodeRegisterType(ntypelist, &sh_node_normal);
nodeRegisterType(ntypelist, &sh_node_geom);
nodeRegisterType(ntypelist, &sh_node_mapping);
nodeRegisterType(ntypelist, &sh_node_curve_vec);
nodeRegisterType(ntypelist, &sh_node_curve_rgb);
nodeRegisterType(ntypelist, &sh_node_math);
nodeRegisterType(ntypelist, &sh_node_vect_math);
nodeRegisterType(ntypelist, &sh_node_squeeze);
nodeRegisterType(ntypelist, &sh_node_camera);
nodeRegisterType(ntypelist, &sh_node_material);
nodeRegisterType(ntypelist, &sh_node_material_ext);
nodeRegisterType(ntypelist, &sh_node_value);
nodeRegisterType(ntypelist, &sh_node_rgb);
nodeRegisterType(ntypelist, &sh_node_texture);
nodeRegisterType(ntypelist, &node_dynamic_typeinfo);
nodeRegisterType(ntypelist, &sh_node_invert);
nodeRegisterType(ntypelist, &sh_node_seprgb);
nodeRegisterType(ntypelist, &sh_node_combrgb);
nodeRegisterType(ntypelist, &sh_node_hue_sat);
}
static void registerTextureNodes(ListBase *ntypelist)
{
nodeRegisterType(ntypelist, &node_group_typeinfo);
nodeRegisterType(ntypelist, &tex_node_math);
nodeRegisterType(ntypelist, &tex_node_mix_rgb);
nodeRegisterType(ntypelist, &tex_node_valtorgb);
nodeRegisterType(ntypelist, &tex_node_rgbtobw);
nodeRegisterType(ntypelist, &tex_node_valtonor);
nodeRegisterType(ntypelist, &tex_node_curve_rgb);
nodeRegisterType(ntypelist, &tex_node_curve_time);
nodeRegisterType(ntypelist, &tex_node_invert);
nodeRegisterType(ntypelist, &tex_node_hue_sat);
nodeRegisterType(ntypelist, &tex_node_coord);
nodeRegisterType(ntypelist, &tex_node_distance);
nodeRegisterType(ntypelist, &tex_node_compose);
nodeRegisterType(ntypelist, &tex_node_decompose);
nodeRegisterType(ntypelist, &tex_node_output);
nodeRegisterType(ntypelist, &tex_node_viewer);
nodeRegisterType(ntypelist, &tex_node_checker);
nodeRegisterType(ntypelist, &tex_node_texture);
nodeRegisterType(ntypelist, &tex_node_bricks);
nodeRegisterType(ntypelist, &tex_node_image);
nodeRegisterType(ntypelist, &tex_node_rotate);
nodeRegisterType(ntypelist, &tex_node_translate);
nodeRegisterType(ntypelist, &tex_node_scale);
nodeRegisterType(ntypelist, &tex_node_at);
nodeRegisterType(ntypelist, &tex_node_proc_voronoi);
nodeRegisterType(ntypelist, &tex_node_proc_blend);
nodeRegisterType(ntypelist, &tex_node_proc_magic);
nodeRegisterType(ntypelist, &tex_node_proc_marble);
nodeRegisterType(ntypelist, &tex_node_proc_clouds);
nodeRegisterType(ntypelist, &tex_node_proc_wood);
nodeRegisterType(ntypelist, &tex_node_proc_musgrave);
nodeRegisterType(ntypelist, &tex_node_proc_noise);
nodeRegisterType(ntypelist, &tex_node_proc_stucci);
nodeRegisterType(ntypelist, &tex_node_proc_distnoise);
}
static void remove_dynamic_typeinfos(ListBase *list)
{
bNodeType *ntype= list->first;
bNodeType *next= NULL;
while(ntype) {
next= ntype->next;
if(ntype->type==NODE_DYNAMIC && ntype->id!=NULL) {
BLI_remlink(list, ntype);
if(ntype->inputs) {
bNodeSocketType *sock= ntype->inputs;
while(sock->type!=-1) {
MEM_freeN(sock->name);
sock++;
}
MEM_freeN(ntype->inputs);
}
if(ntype->outputs) {
bNodeSocketType *sock= ntype->outputs;
while(sock->type!=-1) {
MEM_freeN(sock->name);
sock++;
}
MEM_freeN(ntype->outputs);
}
if(ntype->name) {
MEM_freeN(ntype->name);
}
MEM_freeN(ntype);
}
ntype= next;
}
}
void init_nodesystem(void)
{
registerCompositNodes(&node_all_composit);
registerShaderNodes(&node_all_shaders);
registerTextureNodes(&node_all_textures);
}
void free_nodesystem(void)
{
/*remove_dynamic_typeinfos(&node_all_composit);*/ /* unused for now */
BLI_freelistN(&node_all_composit);
remove_dynamic_typeinfos(&node_all_shaders);
BLI_freelistN(&node_all_shaders);
BLI_freelistN(&node_all_textures);
}
/* called from unlink_scene, when deleting a scene goes over all scenes
* other than the input, checks if they have render layer nodes referencing
* the to-be-deleted scene, and resets them to NULL. */
/* XXX needs to get current scene then! */
void clear_scene_in_nodes(Main *bmain, Scene *sce)
{
Scene *sce1;
bNode *node;
for(sce1= bmain->scene.first; sce1; sce1=sce1->id.next) {
if(sce1!=sce) {
if(sce1->nodetree) {
for(node= sce1->nodetree->nodes.first; node; node= node->next) {
if(node->type==CMP_NODE_R_LAYERS) {
Scene *nodesce= (Scene *)node->id;
if (nodesce==sce) node->id = NULL;
}
}
}
}
}
}
for(node= ntree->