/* Returns a list of DupliObject * note; group dupli's already set transform matrix. see note in group_duplilist() */ ListBase *object_duplilist(Scene *sce, Object *ob) { ListBase *duplilist= MEM_mallocN(sizeof(ListBase), "duplilist"); duplilist->first= duplilist->last= NULL; object_duplilist_recursive((ID *)sce, sce, ob, duplilist, NULL, 0, 0); return duplilist; }
static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int persistent_id[MAX_DUPLI_RECUR], int level, short flag) { DupliObject *dob; Group *group; GroupObject *go; float mat[4][4], tmat[4][4], id; if (ob->dup_group == NULL) return; group = ob->dup_group; /* simple preventing of too deep nested groups */ if (level > MAX_DUPLI_RECUR) return; /* handles animated groups, and */ /* we need to check update for objects that are not in scene... */ if (flag & DUPLILIST_DO_UPDATE) { /* note: update is optional because we don't always need object * transformations to be correct. Also fixes bug [#29616]. */ group_handle_recalc_and_update(scene, ob, group); } if (group_is_animated(ob, group)) flag |= DUPLILIST_ANIMATED; for (go = group->gobject.first, id = 0; go; go = go->next, id++) { /* note, if you check on layer here, render goes wrong... it still deforms verts and uses parent imat */ if (go->ob != ob) { /* group dupli offset, should apply after everything else */ if (!is_zero_v3(group->dupli_ofs)) { copy_m4_m4(tmat, go->ob->obmat); sub_v3_v3v3(tmat[3], tmat[3], group->dupli_ofs); mult_m4_m4m4(mat, ob->obmat, tmat); } else { mult_m4_m4m4(mat, ob->obmat, go->ob->obmat); } dob = new_dupli_object(lb, go->ob, mat, ob->lay, persistent_id, level, id, OB_DUPLIGROUP, flag); /* check the group instance and object layers match, also that the object visible flags are ok. */ if ((dob->origlay & group->layer) == 0 || ((G.is_rendering == FALSE) && dob->ob->restrictflag & OB_RESTRICT_VIEW) || ((G.is_rendering == TRUE) && dob->ob->restrictflag & OB_RESTRICT_RENDER)) { dob->no_draw = TRUE; } if (go->ob->transflag & OB_DUPLI) { copy_m4_m4(dob->ob->obmat, dob->mat); object_duplilist_recursive(&group->id, scene, go->ob, lb, ob->obmat, persistent_id, level + 1, id, flag); copy_m4_m4(dob->ob->obmat, dob->omat); } } } }
static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int level, int animated) { DupliObject *dob; Group *group; GroupObject *go; float mat[4][4], tmat[4][4]; if (ob->dup_group==NULL) return; group= ob->dup_group; /* simple preventing of too deep nested groups */ if (level>MAX_DUPLI_RECUR) return; /* handles animated groups, and */ /* we need to check update for objects that are not in scene... */ group_handle_recalc_and_update(scene, ob, group); animated= animated || group_is_animated(ob, group); for (go= group->gobject.first; go; go= go->next) { /* note, if you check on layer here, render goes wrong... it still deforms verts and uses parent imat */ if (go->ob!=ob) { /* group dupli offset, should apply after everything else */ if (!is_zero_v3(group->dupli_ofs)) { copy_m4_m4(tmat, go->ob->obmat); sub_v3_v3v3(tmat[3], tmat[3], group->dupli_ofs); mult_m4_m4m4(mat, ob->obmat, tmat); } else { mult_m4_m4m4(mat, ob->obmat, go->ob->obmat); } dob= new_dupli_object(lb, go->ob, mat, ob->lay, 0, OB_DUPLIGROUP, animated); /* check the group instance and object layers match, also that the object visible flags are ok. */ if ( (dob->origlay & group->layer)==0 || (G.rendering==0 && dob->ob->restrictflag & OB_RESTRICT_VIEW) || (G.rendering && dob->ob->restrictflag & OB_RESTRICT_RENDER) ) { dob->no_draw= 1; } else { dob->no_draw= 0; } if (go->ob->transflag & OB_DUPLI) { copy_m4_m4(dob->ob->obmat, dob->mat); object_duplilist_recursive(&group->id, scene, go->ob, lb, ob->obmat, level+1, animated); copy_m4_m4(dob->ob->obmat, dob->omat); } } } }
/* Returns a list of DupliObject * note; group dupli's already set transform matrix. see note in group_duplilist() */ ListBase *object_duplilist_ex(Scene *sce, Object *ob, int update, int for_render) { ListBase *duplilist = MEM_mallocN(sizeof(ListBase), "duplilist"); int persistent_id[MAX_DUPLI_RECUR] = {0}; int flag = 0; if (update) flag |= DUPLILIST_DO_UPDATE; if (for_render) flag |= DUPLILIST_FOR_RENDER; duplilist->first = duplilist->last = NULL; object_duplilist_recursive((ID *)sce, sce, ob, duplilist, NULL, persistent_id, 0, 0, flag); return duplilist; }
static void vertex_dupli__mapFunc(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]) { DupliObject *dob; vertexDupliData *vdd= userData; float vec[3], q2[4], mat[3][3], tmat[4][4], obmat[4][4]; int origlay; mul_v3_m4v3(vec, vdd->pmat, co); sub_v3_v3(vec, vdd->pmat[3]); add_v3_v3(vec, vdd->obmat[3]); copy_m4_m4(obmat, vdd->obmat); copy_v3_v3(obmat[3], vec); if (vdd->par->transflag & OB_DUPLIROT) { if (no_f) { vec[0]= -no_f[0]; vec[1]= -no_f[1]; vec[2]= -no_f[2]; } else if (no_s) { vec[0]= -no_s[0]; vec[1]= -no_s[1]; vec[2]= -no_s[2]; } vec_to_quat( q2,vec, vdd->ob->trackflag, vdd->ob->upflag); quat_to_mat3( mat,q2); copy_m4_m4(tmat, obmat); mul_m4_m4m3(obmat, tmat, mat); } origlay = vdd->ob->lay; dob= new_dupli_object(vdd->lb, vdd->ob, obmat, vdd->par->lay, index, OB_DUPLIVERTS, vdd->animated); /* restore the original layer so that each dupli will have proper dob->origlay */ vdd->ob->lay = origlay; if (vdd->orco) copy_v3_v3(dob->orco, vdd->orco[index]); if (vdd->ob->transflag & OB_DUPLI) { float tmpmat[4][4]; copy_m4_m4(tmpmat, vdd->ob->obmat); copy_m4_m4(vdd->ob->obmat, obmat); /* pretend we are really this mat */ object_duplilist_recursive((ID *)vdd->id, vdd->scene, vdd->ob, vdd->lb, obmat, vdd->level+1, vdd->animated); copy_m4_m4(vdd->ob->obmat, tmpmat); } }
static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int level, int animated) { DupliObject *dob; Group *group; GroupObject *go; float mat[4][4], tmat[4][4]; if(ob->dup_group==NULL) return; group= ob->dup_group; /* simple preventing of too deep nested groups */ if(level>MAX_DUPLI_RECUR) return; /* handles animated groups, and */ /* we need to check update for objects that are not in scene... */ group_handle_recalc_and_update(scene, ob, group); animated= animated || group_is_animated(ob, group); for(go= group->gobject.first; go; go= go->next) { /* note, if you check on layer here, render goes wrong... it still deforms verts and uses parent imat */ if(go->ob!=ob) { /* Group Dupli Offset, should apply after everything else */ if (group->dupli_ofs[0] || group->dupli_ofs[1] || group->dupli_ofs[2]) { Mat4CpyMat4(tmat, go->ob->obmat); VecSubf(tmat[3], tmat[3], group->dupli_ofs); Mat4MulMat4(mat, tmat, ob->obmat); } else { Mat4MulMat4(mat, go->ob->obmat, ob->obmat); } dob= new_dupli_object(lb, go->ob, mat, ob->lay, 0, OB_DUPLIGROUP, animated); dob->no_draw= (dob->origlay & group->layer)==0; if(go->ob->transflag & OB_DUPLI) { Mat4CpyMat4(dob->ob->obmat, dob->mat); object_duplilist_recursive((ID *)group, scene, go->ob, lb, ob->obmat, level+1, animated); Mat4CpyMat4(dob->ob->obmat, dob->omat); } } } }
static void vertex_dupli__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s) { DupliObject *dob; struct vertexDupliData *vdd= userData; float vec[3], q2[4], mat[3][3], tmat[4][4], obmat[4][4]; VECCOPY(vec, co); Mat4MulVecfl(vdd->pmat, vec); VecSubf(vec, vec, vdd->pmat[3]); VecAddf(vec, vec, vdd->obmat[3]); Mat4CpyMat4(obmat, vdd->obmat); VECCOPY(obmat[3], vec); if(vdd->par->transflag & OB_DUPLIROT) { if(no_f) { vec[0]= -no_f[0]; vec[1]= -no_f[1]; vec[2]= -no_f[2]; } else if(no_s) { vec[0]= -no_s[0]; vec[1]= -no_s[1]; vec[2]= -no_s[2]; } vectoquat(vec, vdd->ob->trackflag, vdd->ob->upflag, q2); QuatToMat3(q2, mat); Mat4CpyMat4(tmat, obmat); Mat4MulMat43(obmat, tmat, mat); } dob= new_dupli_object(vdd->lb, vdd->ob, obmat, vdd->par->lay, index, OB_DUPLIVERTS, vdd->animated); if(vdd->orco) VECCOPY(dob->orco, vdd->orco[index]); if(vdd->ob->transflag & OB_DUPLI) { float tmpmat[4][4]; Mat4CpyMat4(tmpmat, vdd->ob->obmat); Mat4CpyMat4(vdd->ob->obmat, obmat); /* pretend we are really this mat */ object_duplilist_recursive((ID *)vdd->id, vdd->scene, vdd->ob, vdd->lb, obmat, vdd->level+1, vdd->animated); Mat4CpyMat4(vdd->ob->obmat, tmpmat); } }
static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int level, int animated) { Object *ob, *ob_iter; Base *base = NULL; DupliObject *dob; DerivedMesh *dm; Mesh *me= par->data; MLoopUV *mloopuv; MPoly *mpoly, *mp; MLoop *mloop; MVert *mvert; float pmat[4][4], imat[3][3], (*orco)[3] = NULL, w; int lay, oblay, totface, a; Scene *sce = NULL; Group *group = NULL; GroupObject *go = NULL; BMEditMesh *em; float ob__obmat[4][4]; /* needed for groups where the object matrix needs to be modified */ /* simple preventing of too deep nested groups */ if (level>MAX_DUPLI_RECUR) return; copy_m4_m4(pmat, par->obmat); em = me->edit_btmesh; if (em) { dm= editbmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH); } else { dm = mesh_get_derived_deform(scene, par, CD_MASK_BAREMESH); } totface= dm->getNumPolys(dm); mpoly= dm->getPolyArray(dm); mloop= dm->getLoopArray(dm); mvert= dm->getVertArray(dm); if (G.rendering) { orco= (float(*)[3])get_mesh_orco_verts(par); transform_mesh_orco_verts(me, orco, me->totvert, 0); mloopuv= me->mloopuv; } else { orco= NULL; mloopuv= NULL; } /* having to loop on scene OR group objects is NOT FUN */ if (GS(id->name) == ID_SCE) { sce = (Scene *)id; lay= sce->lay; base= sce->base.first; } else { group = (Group *)id; lay= group->layer; go = group->gobject.first; } /* Start looping on Scene OR Group objects */ while (base || go) { if (sce) { ob_iter= base->object; oblay = base->lay; } else { ob_iter= go->ob; oblay = ob_iter->lay; } if (lay & oblay && scene->obedit!=ob_iter) { ob=ob_iter->parent; while (ob) { if (ob==par) { ob = ob_iter; /* End Scene/Group object loop, below is generic */ /* par_space_mat - only used for groups so we can modify the space dupli's are in * when par_space_mat is NULL ob->obmat can be used instead of ob__obmat */ if (par_space_mat) mult_m4_m4m4(ob__obmat, par_space_mat, ob->obmat); else copy_m4_m4(ob__obmat, ob->obmat); copy_m3_m4(imat, ob->parentinv); /* mballs have a different dupli handling */ if (ob->type!=OB_MBALL) ob->flag |= OB_DONE; /* doesnt render */ for (a=0, mp= mpoly; a<totface; a++, mp++) { int mv1; int mv2; int mv3; /* int mv4; */ /* UNUSED */ float *v1; float *v2; float *v3; /* float *v4; */ /* UNUSED */ float cent[3], quat[4], mat[3][3], mat3[3][3], tmat[4][4], obmat[4][4]; MLoop *loopstart= mloop + mp->loopstart; if (mp->totloop < 3) { /* highly unlikely but to be safe */ continue; } else { v1= mvert[(mv1= loopstart[0].v)].co; v2= mvert[(mv2= loopstart[1].v)].co; v3= mvert[(mv3= loopstart[2].v)].co; #if 0 if (mp->totloop > 3) { v4= mvert[(mv4= loopstart[3].v)].co; } #endif } /* translation */ mesh_calc_poly_center(mp, loopstart, mvert, cent); mul_m4_v3(pmat, cent); sub_v3_v3v3(cent, cent, pmat[3]); add_v3_v3(cent, ob__obmat[3]); copy_m4_m4(obmat, ob__obmat); copy_v3_v3(obmat[3], cent); /* rotation */ tri_to_quat( quat,v1, v2, v3); quat_to_mat3( mat,quat); /* scale */ if (par->transflag & OB_DUPLIFACES_SCALE) { float size= mesh_calc_poly_area(mp, loopstart, mvert, NULL); size= sqrtf(size) * par->dupfacesca; mul_m3_fl(mat, size); } copy_m3_m3(mat3, mat); mul_m3_m3m3(mat, imat, mat3); copy_m4_m4(tmat, obmat); mul_m4_m4m3(obmat, tmat, mat); dob= new_dupli_object(lb, ob, obmat, par->lay, a, OB_DUPLIFACES, animated); if (G.rendering) { w= 1.0f / (float)mp->totloop; if (orco) { int j; for (j = 0; j < mpoly->totloop; j++) { madd_v3_v3fl(dob->orco, orco[loopstart[j].v], w); } } if (mloopuv) { int j; for (j = 0; j < mpoly->totloop; j++) { madd_v2_v2fl(dob->orco, mloopuv[loopstart[j].v].uv, w); } } } if (ob->transflag & OB_DUPLI) { float tmpmat[4][4]; copy_m4_m4(tmpmat, ob->obmat); copy_m4_m4(ob->obmat, obmat); /* pretend we are really this mat */ object_duplilist_recursive((ID *)id, scene, ob, lb, ob->obmat, level+1, animated); copy_m4_m4(ob->obmat, tmpmat); } } break; } ob= ob->parent; } } if (sce) base= base->next; /* scene loop */ else go= go->next; /* group loop */ } if (orco) MEM_freeN(orco); dm->release(dm); }
static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int level, int animated) { Object *ob, *ob_iter; Base *base = NULL; DupliObject *dob; DerivedMesh *dm; Mesh *me= par->data; MTFace *mtface; MFace *mface; MVert *mvert; float pmat[4][4], imat[3][3], (*orco)[3] = NULL, w; int lay, oblay, totface, a; Scene *sce = NULL; Group *group = NULL; GroupObject *go = NULL; EditMesh *em; float ob__obmat[4][4]; /* needed for groups where the object matrix needs to be modified */ /* simple preventing of too deep nested groups */ if(level>MAX_DUPLI_RECUR) return; Mat4CpyMat4(pmat, par->obmat); em = BKE_mesh_get_editmesh(me); if(em) { int totvert; dm= editmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH); totface= dm->getNumFaces(dm); mface= MEM_mallocN(sizeof(MFace)*totface, "mface temp"); dm->copyFaceArray(dm, mface); totvert= dm->getNumVerts(dm); mvert= MEM_mallocN(sizeof(MVert)*totvert, "mvert temp"); dm->copyVertArray(dm, mvert); BKE_mesh_end_editmesh(me, em); } else { dm = mesh_get_derived_deform(scene, par, CD_MASK_BAREMESH); totface= dm->getNumFaces(dm); mface= dm->getFaceArray(dm); mvert= dm->getVertArray(dm); } if(G.rendering) { orco= (float(*)[3])get_mesh_orco_verts(par); transform_mesh_orco_verts(me, orco, me->totvert, 0); mtface= me->mtface; } else { orco= NULL; mtface= NULL; } /* having to loop on scene OR group objects is NOT FUN */ if (GS(id->name) == ID_SCE) { sce = (Scene *)id; lay= sce->lay; base= sce->base.first; } else { group = (Group *)id; lay= group->layer; go = group->gobject.first; } /* Start looping on Scene OR Group objects */ while (base || go) { if (sce) { ob_iter= base->object; oblay = base->lay; } else { ob_iter= go->ob; oblay = ob_iter->lay; } if (lay & oblay && scene->obedit!=ob_iter) { ob=ob_iter->parent; while(ob) { if(ob==par) { ob = ob_iter; /* End Scene/Group object loop, below is generic */ /* par_space_mat - only used for groups so we can modify the space dupli's are in when par_space_mat is NULL ob->obmat can be used instead of ob__obmat */ if(par_space_mat) Mat4MulMat4(ob__obmat, ob->obmat, par_space_mat); else Mat4CpyMat4(ob__obmat, ob->obmat); Mat3CpyMat4(imat, ob->parentinv); /* mballs have a different dupli handling */ if(ob->type!=OB_MBALL) ob->flag |= OB_DONE; /* doesnt render */ for(a=0; a<totface; a++) { int mv1 = mface[a].v1; int mv2 = mface[a].v2; int mv3 = mface[a].v3; int mv4 = mface[a].v4; float *v1= mvert[mv1].co; float *v2= mvert[mv2].co; float *v3= mvert[mv3].co; float *v4= (mv4)? mvert[mv4].co: NULL; float cent[3], quat[4], mat[3][3], mat3[3][3], tmat[4][4], obmat[4][4]; /* translation */ if(v4) CalcCent4f(cent, v1, v2, v3, v4); else CalcCent3f(cent, v1, v2, v3); Mat4MulVecfl(pmat, cent); VecSubf(cent, cent, pmat[3]); VecAddf(cent, cent, ob__obmat[3]); Mat4CpyMat4(obmat, ob__obmat); VECCOPY(obmat[3], cent); /* rotation */ triatoquat(v1, v2, v3, quat); QuatToMat3(quat, mat); /* scale */ if(par->transflag & OB_DUPLIFACES_SCALE) { float size= v4?AreaQ3Dfl(v1, v2, v3, v4):AreaT3Dfl(v1, v2, v3); size= sqrt(size) * par->dupfacesca; Mat3MulFloat(mat[0], size); } Mat3CpyMat3(mat3, mat); Mat3MulMat3(mat, imat, mat3); Mat4CpyMat4(tmat, obmat); Mat4MulMat43(obmat, tmat, mat); dob= new_dupli_object(lb, ob, obmat, lay, a, OB_DUPLIFACES, animated); if(G.rendering) { w= (mv4)? 0.25f: 1.0f/3.0f; if(orco) { VECADDFAC(dob->orco, dob->orco, orco[mv1], w); VECADDFAC(dob->orco, dob->orco, orco[mv2], w); VECADDFAC(dob->orco, dob->orco, orco[mv3], w); if(mv4) VECADDFAC(dob->orco, dob->orco, orco[mv4], w); } if(mtface) { dob->uv[0] += w*mtface[a].uv[0][0]; dob->uv[1] += w*mtface[a].uv[0][1]; dob->uv[0] += w*mtface[a].uv[1][0]; dob->uv[1] += w*mtface[a].uv[1][1]; dob->uv[0] += w*mtface[a].uv[2][0]; dob->uv[1] += w*mtface[a].uv[2][1]; if(mv4) { dob->uv[0] += w*mtface[a].uv[3][0]; dob->uv[1] += w*mtface[a].uv[3][1]; } } } if(ob->transflag & OB_DUPLI) { float tmpmat[4][4]; Mat4CpyMat4(tmpmat, ob->obmat); Mat4CpyMat4(ob->obmat, obmat); /* pretend we are really this mat */ object_duplilist_recursive((ID *)id, scene, ob, lb, ob->obmat, level+1, animated); Mat4CpyMat4(ob->obmat, tmpmat); } } break; } ob= ob->parent; } } if (sce) base= base->next; /* scene loop */ else go= go->next; /* group loop */ } if(par->mode & OB_MODE_EDIT) { MEM_freeN(mface); MEM_freeN(mvert); } if(orco) MEM_freeN(orco); dm->release(dm); }