void meshobject_foreachScreenVert( ViewContext *vc, void (*func)(void *userData, MVert *eve, const float screen_co[2], int index), void *userData, eV3DProjTest clip_flag) { foreachScreenObjectVert_userData data; DerivedMesh *dm = mesh_get_derived_deform(vc->scene, vc->obact, CD_MASK_BAREMESH); data.vc = *vc; data.func = func; data.userData = userData; data.clip_flag = clip_flag; if (clip_flag & V3D_PROJ_TEST_CLIP_BB) { ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */ } dm->foreachMappedVert(dm, meshobject_foreachScreenVert__mapFunc, &data); dm->release(dm); }
static void draw_mesh_text(Scene *scene, Object *ob, int glsl) { Mesh *me = ob->data; DerivedMesh *ddm; MPoly *mp, *mface = me->mpoly; MTexPoly *mtpoly = me->mtpoly; MLoopUV *mloopuv = me->mloopuv; MLoopUV *luv; MLoopCol *mloopcol = me->mloopcol; /* why does mcol exist? */ MLoopCol *lcol; bProperty *prop = BKE_bproperty_object_get(ob, "Text"); GPUVertexAttribs gattribs; int a, totpoly = me->totpoly; /* fake values to pass to GPU_render_text() */ MCol tmp_mcol[4] = {{0}}; MCol *tmp_mcol_pt = mloopcol ? tmp_mcol : NULL; MTFace tmp_tf = {{{0}}}; /* don't draw without tfaces */ if (!mtpoly || !mloopuv) return; /* don't draw when editing */ if (ob->mode & OB_MODE_EDIT) return; else if (ob == OBACT) if (BKE_paint_select_elem_test(ob)) return; ddm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); for (a = 0, mp = mface; a < totpoly; a++, mtpoly++, mp++) { short matnr = mp->mat_nr; int mf_smooth = mp->flag & ME_SMOOTH; Material *mat = (me->mat) ? me->mat[matnr] : NULL; int mode = mat ? mat->game.flag : GEMAT_INVISIBLE; if (!(mode & GEMAT_INVISIBLE) && (mode & GEMAT_TEXT) && mp->totloop >= 3) { /* get the polygon as a tri/quad */ int mp_vi[4]; float v1[3], v2[3], v3[3], v4[3]; char string[MAX_PROPSTRING]; int characters, i, glattrib = -1, badtex = 0; /* TEXFACE */ ME_MTEXFACE_CPY(&tmp_tf, mtpoly); if (glsl) { GPU_enable_material(matnr + 1, &gattribs); for (i = 0; i < gattribs.totlayer; i++) { if (gattribs.layer[i].type == CD_MTFACE) { glattrib = gattribs.layer[i].glindex; break; } } } else { badtex = set_draw_settings_cached(0, &tmp_tf, mat, Gtexdraw); if (badtex) { continue; } } mp_vi[0] = me->mloop[mp->loopstart + 0].v; mp_vi[1] = me->mloop[mp->loopstart + 1].v; mp_vi[2] = me->mloop[mp->loopstart + 2].v; mp_vi[3] = (mp->totloop >= 4) ? me->mloop[mp->loopstart + 3].v : 0; /* UV */ luv = &mloopuv[mp->loopstart]; copy_v2_v2(tmp_tf.uv[0], luv->uv); luv++; copy_v2_v2(tmp_tf.uv[1], luv->uv); luv++; copy_v2_v2(tmp_tf.uv[2], luv->uv); luv++; if (mp->totloop >= 4) { copy_v2_v2(tmp_tf.uv[3], luv->uv); } /* COLOR */ if (mloopcol) { unsigned int totloop_clamp = min_ii(4, mp->totloop); unsigned int j; lcol = &mloopcol[mp->loopstart]; for (j = 0; j < totloop_clamp; j++, lcol++) { MESH_MLOOPCOL_TO_MCOL(lcol, &tmp_mcol[j]); } } /* LOCATION */ ddm->getVertCo(ddm, mp_vi[0], v1); ddm->getVertCo(ddm, mp_vi[1], v2); ddm->getVertCo(ddm, mp_vi[2], v3); if (mp->totloop >= 4) { ddm->getVertCo(ddm, mp_vi[3], v4); } /* The BM_FONT handling is in the gpu module, shared with the * game engine, was duplicated previously */ BKE_bproperty_set_valstr(prop, string); characters = strlen(string); if (!BKE_image_has_ibuf(mtpoly->tpage, NULL)) characters = 0; if (!mf_smooth) { float nor[3]; normal_tri_v3(nor, v1, v2, v3); glNormal3fv(nor); } GPU_render_text(&tmp_tf, mode, string, characters, (unsigned int *)tmp_mcol_pt, v1, v2, v3, (mp->totloop >= 4 ? v4 : NULL), glattrib); } } ddm->release(ddm); }
static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int level, int animated) { Object *ob, *ob_iter; Mesh *me= par->data; Base *base = NULL; DerivedMesh *dm; vertexDupliData vdd; Scene *sce = NULL; Group *group = NULL; GroupObject * go = NULL; BMEditMesh *em; float vec[3], no[3], pmat[4][4]; int totvert, a, oblay; unsigned int lay; copy_m4_m4(pmat, par->obmat); /* simple preventing of too deep nested groups */ if (level>MAX_DUPLI_RECUR) return; 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); if (G.rendering) { vdd.orco= (float(*)[3])get_mesh_orco_verts(par); transform_mesh_orco_verts(me, vdd.orco, me->totvert, 0); } else vdd.orco= NULL; totvert = dm->getNumVerts(dm); /* 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(vdd.obmat, par_space_mat, ob->obmat); else copy_m4_m4(vdd.obmat, ob->obmat); vdd.id= id; vdd.level= level; vdd.animated= animated; vdd.lb= lb; vdd.ob= ob; vdd.scene= scene; vdd.par= par; copy_m4_m4(vdd.pmat, pmat); /* mballs have a different dupli handling */ if (ob->type!=OB_MBALL) ob->flag |= OB_DONE; /* doesnt render */ if (me->edit_btmesh) { dm->foreachMappedVert(dm, vertex_dupli__mapFunc, (void*) &vdd); } else { for (a=0; a<totvert; a++) { dm->getVertCo(dm, a, vec); dm->getVertNo(dm, a, no); vertex_dupli__mapFunc(&vdd, a, vec, no, NULL); } } if (sce) { /* Set proper layer in case of scene looping, * in case of groups the object layer will be * changed when it's duplicated due to the * group duplication. */ ob->lay = vdd.par->lay; } break; } ob= ob->parent; } } if (sce) base= base->next; /* scene loop */ else go= go->next; /* group loop */ } if (vdd.orco) MEM_freeN(vdd.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; 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); }
int join_mesh_shapes_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); Mesh *me= (Mesh *)ob->data; Mesh *selme=NULL; DerivedMesh *dm=NULL; Key *key=me->key; KeyBlock *kb; int ok=0, nonequal_verts=0; CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { if (base->object == ob) continue; if (base->object->type==OB_MESH) { selme = (Mesh *)base->object->data; if (selme->totvert==me->totvert) ok++; else nonequal_verts=1; } } CTX_DATA_END; if (!ok) { if (nonequal_verts) BKE_report(op->reports, RPT_WARNING, "Selected meshes must have equal numbers of vertices"); else BKE_report(op->reports, RPT_WARNING, "No additional selected meshes with equal vertex count to join"); return OPERATOR_CANCELLED; } if(key == NULL) { key= me->key= add_key((ID *)me); key->type= KEY_RELATIVE; /* first key added, so it was the basis. initialise it with the existing mesh */ kb= add_keyblock(key, NULL); mesh_to_key(me, kb); } /* now ready to add new keys from selected meshes */ CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { if (base->object == ob) continue; if(base->object->type==OB_MESH) { selme = (Mesh *)base->object->data; if (selme->totvert==me->totvert) { dm = mesh_get_derived_deform(scene, base->object, CD_MASK_BAREMESH); if (!dm) continue; kb= add_keyblock(key, base->object->id.name+2); DM_to_meshkey(dm, me, kb); dm->release(dm); } } } CTX_DATA_END; WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene); return OPERATOR_FINISHED; }
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); }
/* from/to_world_space : whether from/to particles are in world or hair space * from/to_mat : additional transform for from/to particles (e.g. for using object space copying) */ static bool remap_hair_emitter(Scene *scene, Object *ob, ParticleSystem *psys, Object *target_ob, ParticleSystem *target_psys, PTCacheEdit *target_edit, float from_mat[4][4], float to_mat[4][4], bool from_global, bool to_global) { ParticleSystemModifierData *target_psmd = psys_get_modifier(target_ob, target_psys); ParticleData *pa, *tpa; PTCacheEditPoint *edit_point; PTCacheEditKey *ekey; BVHTreeFromMesh bvhtree= {NULL}; MFace *mface = NULL, *mf; MEdge *medge = NULL, *me; MVert *mvert; DerivedMesh *dm, *target_dm; int numverts; int i, k; float from_ob_imat[4][4], to_ob_imat[4][4]; float from_imat[4][4], to_imat[4][4]; if (!target_psmd->dm) return false; if (!psys->part || psys->part->type != PART_HAIR) return false; if (!target_psys->part || target_psys->part->type != PART_HAIR) return false; edit_point = target_edit ? target_edit->points : NULL; invert_m4_m4(from_ob_imat, ob->obmat); invert_m4_m4(to_ob_imat, target_ob->obmat); invert_m4_m4(from_imat, from_mat); invert_m4_m4(to_imat, to_mat); if (target_psmd->dm->deformedOnly) { /* we don't want to mess up target_psmd->dm when converting to global coordinates below */ dm = target_psmd->dm; } else { /* warning: this rebuilds target_psmd->dm! */ dm = mesh_get_derived_deform(scene, target_ob, CD_MASK_BAREMESH | CD_MASK_MFACE); } target_dm = target_psmd->dm; /* don't modify the original vertices */ dm = CDDM_copy(dm); /* BMESH_ONLY, deform dm may not have tessface */ DM_ensure_tessface(dm); numverts = dm->getNumVerts(dm); mvert = dm->getVertArray(dm); /* convert to global coordinates */ for (i=0; i<numverts; i++) mul_m4_v3(to_mat, mvert[i].co); if (dm->getNumTessFaces(dm) != 0) { mface = dm->getTessFaceArray(dm); bvhtree_from_mesh_faces(&bvhtree, dm, 0.0, 2, 6); } else if (dm->getNumEdges(dm) != 0) { medge = dm->getEdgeArray(dm); bvhtree_from_mesh_edges(&bvhtree, dm, 0.0, 2, 6); } else { dm->release(dm); return false; } for (i = 0, tpa = target_psys->particles, pa = psys->particles; i < target_psys->totpart; i++, tpa++, pa++) { float from_co[3]; BVHTreeNearest nearest; if (from_global) mul_v3_m4v3(from_co, from_ob_imat, pa->hair[0].co); else mul_v3_m4v3(from_co, from_ob_imat, pa->hair[0].world_co); mul_m4_v3(from_mat, from_co); nearest.index = -1; nearest.dist_sq = FLT_MAX; BLI_bvhtree_find_nearest(bvhtree.tree, from_co, &nearest, bvhtree.nearest_callback, &bvhtree); if (nearest.index == -1) { if (G.debug & G_DEBUG) printf("No nearest point found for hair root!"); continue; } if (mface) { float v[4][3]; mf = &mface[nearest.index]; copy_v3_v3(v[0], mvert[mf->v1].co); copy_v3_v3(v[1], mvert[mf->v2].co); copy_v3_v3(v[2], mvert[mf->v3].co); if (mf->v4) { copy_v3_v3(v[3], mvert[mf->v4].co); interp_weights_poly_v3(tpa->fuv, v, 4, nearest.co); } else interp_weights_poly_v3(tpa->fuv, v, 3, nearest.co); tpa->foffset = 0.0f; tpa->num = nearest.index; tpa->num_dmcache = psys_particle_dm_face_lookup(target_ob, target_dm, tpa->num, tpa->fuv, NULL); } else { me = &medge[nearest.index]; tpa->fuv[1] = line_point_factor_v3(nearest.co, mvert[me->v1].co, mvert[me->v2].co); tpa->fuv[0] = 1.0f - tpa->fuv[1]; tpa->fuv[2] = tpa->fuv[3] = 0.0f; tpa->foffset = 0.0f; tpa->num = nearest.index; tpa->num_dmcache = -1; } /* translate hair keys */ { HairKey *key, *tkey; float hairmat[4][4], imat[4][4]; float offset[3]; if (to_global) copy_m4_m4(imat, target_ob->obmat); else { /* note: using target_dm here, which is in target_ob object space and has full modifiers */ psys_mat_hair_to_object(target_ob, target_dm, target_psys->part->from, tpa, hairmat); invert_m4_m4(imat, hairmat); } mul_m4_m4m4(imat, imat, to_imat); /* offset in world space */ sub_v3_v3v3(offset, nearest.co, from_co); if (edit_point) { for (k=0, key=pa->hair, tkey=tpa->hair, ekey = edit_point->keys; k<tpa->totkey; k++, key++, tkey++, ekey++) { float co_orig[3]; if (from_global) mul_v3_m4v3(co_orig, from_ob_imat, key->co); else mul_v3_m4v3(co_orig, from_ob_imat, key->world_co); mul_m4_v3(from_mat, co_orig); add_v3_v3v3(tkey->co, co_orig, offset); mul_m4_v3(imat, tkey->co); ekey->flag |= PEK_USE_WCO; } edit_point++; } else { for (k=0, key=pa->hair, tkey=tpa->hair; k<tpa->totkey; k++, key++, tkey++) { float co_orig[3]; if (from_global) mul_v3_m4v3(co_orig, from_ob_imat, key->co); else mul_v3_m4v3(co_orig, from_ob_imat, key->world_co); mul_m4_v3(from_mat, co_orig); add_v3_v3v3(tkey->co, co_orig, offset); mul_m4_v3(imat, tkey->co); } } } } free_bvhtree_from_mesh(&bvhtree); dm->release(dm); psys_free_path_cache(target_psys, target_edit); PE_update_object(scene, target_ob, 0); return true; }
static int connect_hair(Scene *scene, Object *ob, ParticleSystem *psys) { ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); ParticleData *pa; PTCacheEdit *edit; PTCacheEditPoint *point; PTCacheEditKey *ekey = NULL; HairKey *key; BVHTreeFromMesh bvhtree= {NULL}; BVHTreeNearest nearest; MFace *mface, *mf; MVert *mvert; DerivedMesh *dm = NULL; int numverts; int i, k; float hairmat[4][4], imat[4][4]; float v[4][3], vec[3]; if (!psys || !psys->part || psys->part->type != PART_HAIR || !psmd->dm) return FALSE; edit= psys->edit; point= edit ? edit->points : NULL; if (psmd->dm->deformedOnly) { /* we don't want to mess up psmd->dm when converting to global coordinates below */ dm = psmd->dm; } else { dm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); } /* don't modify the original vertices */ dm = CDDM_copy(dm); /* BMESH_ONLY, deform dm may not have tessface */ DM_ensure_tessface(dm); numverts = dm->getNumVerts(dm); mvert = dm->getVertArray(dm); mface = dm->getTessFaceArray(dm); /* convert to global coordinates */ for (i=0; i<numverts; i++) mul_m4_v3(ob->obmat, mvert[i].co); bvhtree_from_mesh_faces(&bvhtree, dm, 0.0, 2, 6); for (i=0, pa= psys->particles; i<psys->totpart; i++, pa++) { key = pa->hair; nearest.index = -1; nearest.dist = FLT_MAX; BLI_bvhtree_find_nearest(bvhtree.tree, key->co, &nearest, bvhtree.nearest_callback, &bvhtree); if (nearest.index == -1) { if (G.debug & G_DEBUG) printf("No nearest point found for hair root!"); continue; } mf = &mface[nearest.index]; copy_v3_v3(v[0], mvert[mf->v1].co); copy_v3_v3(v[1], mvert[mf->v2].co); copy_v3_v3(v[2], mvert[mf->v3].co); if (mf->v4) { copy_v3_v3(v[3], mvert[mf->v4].co); interp_weights_poly_v3(pa->fuv, v, 4, nearest.co); } else interp_weights_poly_v3(pa->fuv, v, 3, nearest.co); pa->num = nearest.index; pa->num_dmcache = psys_particle_dm_face_lookup(ob, psmd->dm, pa->num, pa->fuv, NULL); psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat); invert_m4_m4(imat, hairmat); sub_v3_v3v3(vec, nearest.co, key->co); if (point) { ekey = point->keys; point++; } for (k=0, key=pa->hair; k<pa->totkey; k++, key++) { add_v3_v3(key->co, vec); mul_m4_v3(imat, key->co); if (ekey) { ekey->flag |= PEK_USE_WCO; ekey++; } } } free_bvhtree_from_mesh(&bvhtree); dm->release(dm); psys_free_path_cache(psys, psys->edit); psys->flag &= ~PSYS_GLOBAL_HAIR; PE_update_object(scene, ob, 0); return TRUE; }