/* Raytracing for vertex to bone/vertex visibility */ static void heat_ray_tree_create(LaplacianSystem *sys) { MFace *mface = sys->heat.mface; float (*verts)[3] = sys->heat.verts; int totface = sys->heat.totface; int totvert = sys->heat.totvert; int a; sys->heat.bvhtree = BLI_bvhtree_new(totface, 0.0f, 4, 6); sys->heat.vface = MEM_callocN(sizeof(MFace*)*totvert, "HeatVFaces"); for(a=0; a<totface; a++) { MFace *mf = mface+a; float bb[6]; INIT_MINMAX(bb, bb+3); DO_MINMAX(verts[mf->v1], bb, bb+3); DO_MINMAX(verts[mf->v2], bb, bb+3); DO_MINMAX(verts[mf->v3], bb, bb+3); if(mf->v4) { DO_MINMAX(verts[mf->v4], bb, bb+3); } BLI_bvhtree_insert(sys->heat.bvhtree, a, bb, 2); //Setup inverse pointers to use on isect.orig sys->heat.vface[mf->v1]= mf; sys->heat.vface[mf->v2]= mf; sys->heat.vface[mf->v3]= mf; if(mf->v4) sys->heat.vface[mf->v4]= mf; } BLI_bvhtree_balance(sys->heat.bvhtree); }
static void calc_ocval_face(float *v1, float *v2, float *v3, float *v4, short x, short y, short z, OcVal *ov) { float min[3], max[3]; int ocmin, ocmax; copy_v3_v3(min, v1); copy_v3_v3(max, v1); DO_MINMAX(v2, min, max); DO_MINMAX(v3, min, max); if(v4) { DO_MINMAX(v4, min, max); } ocmin= OCVALRES*(min[0]-x); ocmax= OCVALRES*(max[0]-x); ov->ocx= BROW16(ocmin, ocmax); ocmin= OCVALRES*(min[1]-y); ocmax= OCVALRES*(max[1]-y); ov->ocy= BROW16(ocmin, ocmax); ocmin= OCVALRES*(min[2]-z); ocmax= OCVALRES*(max[2]-z); ov->ocz= BROW16(ocmin, ocmax); }
void RE_rayobject_merge_bb(RayObject *r, float *min, float *max) { if (RE_rayobject_isRayFace(r)) { RayFace *face = (RayFace*) RE_rayobject_align(r); DO_MINMAX(face->v1, min, max); DO_MINMAX(face->v2, min, max); DO_MINMAX(face->v3, min, max); if (RE_rayface_isQuad(face)) DO_MINMAX(face->v4, min, max); } else if (RE_rayobject_isVlakPrimitive(r)) { VlakPrimitive *face = (VlakPrimitive*) RE_rayobject_align(r); RayFace nface; rayface_from_vlak(&nface, face->ob, face->face); DO_MINMAX(nface.v1, min, max); DO_MINMAX(nface.v2, min, max); DO_MINMAX(nface.v3, min, max); if (RE_rayface_isQuad(&nface)) DO_MINMAX(nface.v4, min, max); } else if (RE_rayobject_isRayAPI(r)) { r = RE_rayobject_align(r); r->api->bb(r, min, max); } else assert(0); }
/* find the bounding box of an objectinstance in global space */ void global_bounds_obi(Render *re, ObjectInstanceRen *obi, float *bbmin, float *bbmax) { ObjectRen *obr = obi->obr; VolumePrecache *vp = obi->volume_precache; VertRen *ver= NULL; float co[3]; int a; if (vp->bbmin != NULL && vp->bbmax != NULL) { copy_v3_v3(bbmin, vp->bbmin); copy_v3_v3(bbmax, vp->bbmax); return; } vp->bbmin = MEM_callocN(sizeof(float)*3, "volume precache min boundbox corner"); vp->bbmax = MEM_callocN(sizeof(float)*3, "volume precache max boundbox corner"); INIT_MINMAX(bbmin, bbmax); for(a=0; a<obr->totvert; a++) { if((a & 255)==0) ver= obr->vertnodes[a>>8].vert; else ver++; copy_v3_v3(co, ver->co); /* transformed object instance in camera space */ if(obi->flag & R_TRANSFORMED) mul_m4_v3(obi->mat, co); /* convert to global space */ mul_m4_v3(re->viewinv, co); DO_MINMAX(co, vp->bbmin, vp->bbmax); }
static void hair_get_boundbox(ClothModifierData *clmd, float gmin[3], float gmax[3]) { Cloth *cloth = clmd->clothObject; Implicit_Data *data = cloth->implicit; unsigned int mvert_num = cloth->mvert_num; int i; INIT_MINMAX(gmin, gmax); for (i = 0; i < mvert_num; i++) { float x[3]; BPH_mass_spring_get_motion_state(data, i, x, NULL); DO_MINMAX(x, gmin, gmax); } }
static void RE_rayobject_instance_bb(RayObject *o, float *min, float *max) { //TODO: // *better bb.. calculated without rotations of bb // *maybe cache that better-fitted-BB at the InstanceRayObject InstanceRayObject *obj = (InstanceRayObject *)o; float m[3], M[3], t[3]; int i, j; INIT_MINMAX(m, M); RE_rayobject_merge_bb(obj->target, m, M); //There must be a faster way than rotating all the 8 vertexs of the BB for (i = 0; i < 8; i++) { for (j = 0; j < 3; j++) t[j] = (i & (1 << j)) ? M[j] : m[j]; mul_m4_v3(obj->target2global, t); DO_MINMAX(t, min, max); } }
ScatterTree *scatter_tree_new(ScatterSettings *ss[3], float scale, float error, float (*co)[3], float (*color)[3], float *area, int totpoint) { ScatterTree *tree; ScatterPoint *points, **refpoints; int i; /* allocate tree */ tree= MEM_callocN(sizeof(ScatterTree), "ScatterTree"); tree->scale= scale; tree->error= error; tree->totpoint= totpoint; tree->ss[0]= ss[0]; tree->ss[1]= ss[1]; tree->ss[2]= ss[2]; points= MEM_callocN(sizeof(ScatterPoint)*totpoint, "ScatterPoints"); refpoints= MEM_callocN(sizeof(ScatterPoint*)*totpoint, "ScatterRefPoints"); tree->points= points; tree->refpoints= refpoints; /* build points */ INIT_MINMAX(tree->min, tree->max); for(i=0; i<totpoint; i++) { copy_v3_v3(points[i].co, co[i]); copy_v3_v3(points[i].rad, color[i]); points[i].area= fabsf(area[i])/(tree->scale*tree->scale); points[i].back= (area[i] < 0.0f); mul_v3_fl(points[i].co, 1.0f/tree->scale); DO_MINMAX(points[i].co, tree->min, tree->max); refpoints[i]= points + i; } return tree; }
void boundbox_mesh(Mesh *me, float *loc, float *size) { MVert *mvert; BoundBox *bb; float min[3], max[3]; float mloc[3], msize[3]; int a; if(me->bb==0) me->bb= MEM_callocN(sizeof(BoundBox), "boundbox"); bb= me->bb; INIT_MINMAX(min, max); if (!loc) loc= mloc; if (!size) size= msize; mvert= me->mvert; for(a=0; a<me->totvert; a++, mvert++) { DO_MINMAX(mvert->co, min, max); } if(!me->totvert) { min[0] = min[1] = min[2] = -1.0f; max[0] = max[1] = max[2] = 1.0f; } loc[0]= (min[0]+max[0])/2.0f; loc[1]= (min[1]+max[1])/2.0f; loc[2]= (min[2]+max[2])/2.0f; size[0]= (max[0]-min[0])/2.0f; size[1]= (max[1]-min[1])/2.0f; size[2]= (max[2]-min[2])/2.0f; boundbox_set_from_min_max(bb, min, max); }
static void harmonic_coordinates_bind(Scene *UNUSED(scene), MeshDeformModifierData *mmd, MeshDeformBind *mdb) { MDefBindInfluence *inf; MDefInfluence *mdinf; MDefCell *cell; float center[3], vec[3], maxwidth, totweight; int a, b, x, y, z, totinside, offset; /* compute bounding box of the cage mesh */ INIT_MINMAX(mdb->min, mdb->max); for(a=0; a<mdb->totcagevert; a++) DO_MINMAX(mdb->cagecos[a], mdb->min, mdb->max); /* allocate memory */ mdb->size= (2<<(mmd->gridsize-1)) + 2; mdb->size3= mdb->size*mdb->size*mdb->size; mdb->tag= MEM_callocN(sizeof(int)*mdb->size3, "MeshDeformBindTag"); mdb->phi= MEM_callocN(sizeof(float)*mdb->size3, "MeshDeformBindPhi"); mdb->totalphi= MEM_callocN(sizeof(float)*mdb->size3, "MeshDeformBindTotalPhi"); mdb->boundisect= MEM_callocN(sizeof(*mdb->boundisect)*mdb->size3, "MDefBoundIsect"); mdb->semibound= MEM_callocN(sizeof(int)*mdb->size3, "MDefSemiBound"); mdb->inside= MEM_callocN(sizeof(int)*mdb->totvert, "MDefInside"); if(mmd->flag & MOD_MDEF_DYNAMIC_BIND) mdb->dyngrid= MEM_callocN(sizeof(MDefBindInfluence*)*mdb->size3, "MDefDynGrid"); else mdb->weights= MEM_callocN(sizeof(float)*mdb->totvert*mdb->totcagevert, "MDefWeights"); mdb->memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "harmonic coords arena"); BLI_memarena_use_calloc(mdb->memarena); /* make bounding box equal size in all directions, add padding, and compute * width of the cells */ maxwidth = -1.0f; for(a=0; a<3; a++) if(mdb->max[a]-mdb->min[a] > maxwidth) maxwidth= mdb->max[a]-mdb->min[a]; for(a=0; a<3; a++) { center[a]= (mdb->min[a]+mdb->max[a])*0.5f; mdb->min[a]= center[a] - maxwidth*0.5f; mdb->max[a]= center[a] + maxwidth*0.5f; mdb->width[a]= (mdb->max[a]-mdb->min[a])/(mdb->size-4); mdb->min[a] -= 2.1f*mdb->width[a]; mdb->max[a] += 2.1f*mdb->width[a]; mdb->width[a]= (mdb->max[a]-mdb->min[a])/mdb->size; mdb->halfwidth[a]= mdb->width[a]*0.5f; } progress_bar(0, "Setting up mesh deform system"); totinside= 0; for(a=0; a<mdb->totvert; a++) { copy_v3_v3(vec, mdb->vertexcos[a]); mdb->inside[a]= meshdeform_inside_cage(mdb, vec); if(mdb->inside[a]) totinside++; } /* free temporary MDefBoundIsects */ BLI_memarena_free(mdb->memarena); mdb->memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "harmonic coords arena"); /* start with all cells untyped */ for(a=0; a<mdb->size3; a++) mdb->tag[a]= MESHDEFORM_TAG_UNTYPED; /* detect intersections and tag boundary cells */ for(z=0; z<mdb->size; z++) for(y=0; y<mdb->size; y++) for(x=0; x<mdb->size; x++) meshdeform_add_intersections(mdb, x, y, z); /* compute exterior and interior tags */ meshdeform_bind_floodfill(mdb); for(z=0; z<mdb->size; z++) for(y=0; y<mdb->size; y++) for(x=0; x<mdb->size; x++) meshdeform_check_semibound(mdb, x, y, z); /* solve */ meshdeform_matrix_solve(mdb); /* assign results */ if(mmd->flag & MOD_MDEF_DYNAMIC_BIND) { mmd->totinfluence= 0; for(a=0; a<mdb->size3; a++) for(inf=mdb->dyngrid[a]; inf; inf=inf->next) mmd->totinfluence++; /* convert MDefBindInfluences to smaller MDefInfluences */ mmd->dyngrid= MEM_callocN(sizeof(MDefCell)*mdb->size3, "MDefDynGrid"); mmd->dyninfluences= MEM_callocN(sizeof(MDefInfluence)*mmd->totinfluence, "MDefInfluence"); offset= 0; for(a=0; a<mdb->size3; a++) { cell= &mmd->dyngrid[a]; cell->offset= offset; totweight= 0.0f; mdinf= mmd->dyninfluences + cell->offset; for(inf=mdb->dyngrid[a]; inf; inf=inf->next, mdinf++) { mdinf->weight= inf->weight; mdinf->vertex= inf->vertex; totweight += mdinf->weight; cell->totinfluence++; } if(totweight > 0.0f) { mdinf= mmd->dyninfluences + cell->offset; for(b=0; b<cell->totinfluence; b++, mdinf++) mdinf->weight /= totweight; } offset += cell->totinfluence; } mmd->dynverts= mdb->inside; mmd->dyngridsize= mdb->size; copy_v3_v3(mmd->dyncellmin, mdb->min); mmd->dyncellwidth= mdb->width[0]; MEM_freeN(mdb->dyngrid); } else { mmd->bindweights= mdb->weights; MEM_freeN(mdb->inside); } MEM_freeN(mdb->tag); MEM_freeN(mdb->phi); MEM_freeN(mdb->totalphi); MEM_freeN(mdb->boundisect); MEM_freeN(mdb->semibound); BLI_memarena_free(mdb->memarena); }
static void cuboid_do( CastModifierData *cmd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { MDeformVert *dvert = NULL; Object *ctrl_ob = NULL; int i, defgrp_index; int has_radius = 0; short flag; float fac, facm; float min[3], max[3], bb[8][3]; float center[3] = {0.0f, 0.0f, 0.0f}; float mat[4][4], imat[4][4]; fac = cmd->fac; facm = 1.0f - fac; flag = cmd->flag; ctrl_ob = cmd->object; /* now we check which options the user wants */ /* 1) (flag was checked in the "if (ctrl_ob)" block above) */ /* 2) cmd->radius > 0.0f: only the vertices within this radius from * the center of the effect should be deformed */ if (cmd->radius > FLT_EPSILON) has_radius = 1; /* 3) if we were given a vertex group name, * only those vertices should be affected */ modifier_get_vgroup(ob, dm, cmd->defgrp_name, &dvert, &defgrp_index); if (ctrl_ob) { if(flag & MOD_CAST_USE_OB_TRANSFORM) { invert_m4_m4(ctrl_ob->imat, ctrl_ob->obmat); mul_m4_m4m4(mat, ob->obmat, ctrl_ob->imat); invert_m4_m4(imat, mat); } invert_m4_m4(ob->imat, ob->obmat); mul_v3_m4v3(center, ob->imat, ctrl_ob->obmat[3]); } if((flag & MOD_CAST_SIZE_FROM_RADIUS) && has_radius) { for(i = 0; i < 3; i++) { min[i] = -cmd->radius; max[i] = cmd->radius; } } else if(!(flag & MOD_CAST_SIZE_FROM_RADIUS) && cmd->size > 0) { for(i = 0; i < 3; i++) { min[i] = -cmd->size; max[i] = cmd->size; } } else { /* get bound box */ /* We can't use the object's bound box because other modifiers * may have changed the vertex data. */ INIT_MINMAX(min, max); /* Cast's center is the ob's own center in its local space, * by default, but if the user defined a control object, we use * its location, transformed to ob's local space. */ if (ctrl_ob) { float vec[3]; /* let the center of the ctrl_ob be part of the bound box: */ DO_MINMAX(center, min, max); for (i = 0; i < numVerts; i++) { sub_v3_v3v3(vec, vertexCos[i], center); DO_MINMAX(vec, min, max); } } else { for (i = 0; i < numVerts; i++) { DO_MINMAX(vertexCos[i], min, max); } } /* we want a symmetric bound box around the origin */ if (fabs(min[0]) > fabs(max[0])) max[0] = fabs(min[0]); if (fabs(min[1]) > fabs(max[1])) max[1] = fabs(min[1]); if (fabs(min[2]) > fabs(max[2])) max[2] = fabs(min[2]); min[0] = -max[0]; min[1] = -max[1]; min[2] = -max[2]; } /* building our custom bounding box */ bb[0][0] = bb[2][0] = bb[4][0] = bb[6][0] = min[0]; bb[1][0] = bb[3][0] = bb[5][0] = bb[7][0] = max[0]; bb[0][1] = bb[1][1] = bb[4][1] = bb[5][1] = min[1]; bb[2][1] = bb[3][1] = bb[6][1] = bb[7][1] = max[1]; bb[0][2] = bb[1][2] = bb[2][2] = bb[3][2] = min[2]; bb[4][2] = bb[5][2] = bb[6][2] = bb[7][2] = max[2]; /* ready to apply the effect, one vertex at a time; * tiny optimization: the code is separated (with parts repeated) * in two possible cases: * with or w/o a vgroup. With lots of if's in the code below, * further optimizations are possible, if needed */ if (dvert) { /* with a vgroup */ float fac_orig = fac; for (i = 0; i < numVerts; i++) { MDeformWeight *dw = NULL; int j, octant, coord; float d[3], dmax, apex[3], fbb; float tmp_co[3]; copy_v3_v3(tmp_co, vertexCos[i]); if(ctrl_ob) { if(flag & MOD_CAST_USE_OB_TRANSFORM) { mul_m4_v3(mat, tmp_co); } else { sub_v3_v3(tmp_co, center); } } if (has_radius) { if (fabsf(tmp_co[0]) > cmd->radius || fabsf(tmp_co[1]) > cmd->radius || fabsf(tmp_co[2]) > cmd->radius) continue; } for (j = 0; j < dvert[i].totweight; ++j) { if(dvert[i].dw[j].def_nr == defgrp_index) { dw = &dvert[i].dw[j]; break; } } if (!dw) continue; fac = fac_orig * dw->weight; facm = 1.0f - fac; /* The algo used to project the vertices to their * bounding box (bb) is pretty simple: * for each vertex v: * 1) find in which octant v is in; * 2) find which outer "wall" of that octant is closer to v; * 3) calculate factor (var fbb) to project v to that wall; * 4) project. */ /* find in which octant this vertex is in */ octant = 0; if (tmp_co[0] > 0.0f) octant += 1; if (tmp_co[1] > 0.0f) octant += 2; if (tmp_co[2] > 0.0f) octant += 4; /* apex is the bb's vertex at the chosen octant */ copy_v3_v3(apex, bb[octant]); /* find which bb plane is closest to this vertex ... */ d[0] = tmp_co[0] / apex[0]; d[1] = tmp_co[1] / apex[1]; d[2] = tmp_co[2] / apex[2]; /* ... (the closest has the higher (closer to 1) d value) */ dmax = d[0]; coord = 0; if (d[1] > dmax) { dmax = d[1]; coord = 1; } if (d[2] > dmax) { /* dmax = d[2]; */ /* commented, we don't need it */ coord = 2; } /* ok, now we know which coordinate of the vertex to use */ if (fabsf(tmp_co[coord]) < FLT_EPSILON) /* avoid division by zero */ continue; /* finally, this is the factor we wanted, to project the vertex * to its bounding box (bb) */ fbb = apex[coord] / tmp_co[coord]; /* calculate the new vertex position */ if (flag & MOD_CAST_X) tmp_co[0] = facm * tmp_co[0] + fac * tmp_co[0] * fbb; if (flag & MOD_CAST_Y) tmp_co[1] = facm * tmp_co[1] + fac * tmp_co[1] * fbb; if (flag & MOD_CAST_Z) tmp_co[2] = facm * tmp_co[2] + fac * tmp_co[2] * fbb; if(ctrl_ob) { if(flag & MOD_CAST_USE_OB_TRANSFORM) { mul_m4_v3(imat, tmp_co); } else { add_v3_v3(tmp_co, center); } } copy_v3_v3(vertexCos[i], tmp_co); } return; } /* no vgroup (check previous case for comments about the code) */ for (i = 0; i < numVerts; i++) { int octant, coord; float d[3], dmax, fbb, apex[3]; float tmp_co[3]; copy_v3_v3(tmp_co, vertexCos[i]); if(ctrl_ob) { if(flag & MOD_CAST_USE_OB_TRANSFORM) { mul_m4_v3(mat, tmp_co); } else { sub_v3_v3(tmp_co, center); } } if (has_radius) { if (fabsf(tmp_co[0]) > cmd->radius || fabsf(tmp_co[1]) > cmd->radius || fabsf(tmp_co[2]) > cmd->radius) continue; } octant = 0; if (tmp_co[0] > 0.0f) octant += 1; if (tmp_co[1] > 0.0f) octant += 2; if (tmp_co[2] > 0.0f) octant += 4; copy_v3_v3(apex, bb[octant]); d[0] = tmp_co[0] / apex[0]; d[1] = tmp_co[1] / apex[1]; d[2] = tmp_co[2] / apex[2]; dmax = d[0]; coord = 0; if (d[1] > dmax) { dmax = d[1]; coord = 1; } if (d[2] > dmax) { /* dmax = d[2]; */ /* commented, we don't need it */ coord = 2; } if (fabsf(tmp_co[coord]) < FLT_EPSILON) continue; fbb = apex[coord] / tmp_co[coord]; if (flag & MOD_CAST_X) tmp_co[0] = facm * tmp_co[0] + fac * tmp_co[0] * fbb; if (flag & MOD_CAST_Y) tmp_co[1] = facm * tmp_co[1] + fac * tmp_co[1] * fbb; if (flag & MOD_CAST_Z) tmp_co[2] = facm * tmp_co[2] + fac * tmp_co[2] * fbb; if(ctrl_ob) { if(flag & MOD_CAST_USE_OB_TRANSFORM) { mul_m4_v3(imat, tmp_co); } else { add_v3_v3(tmp_co, center); } } copy_v3_v3(vertexCos[i], tmp_co); } }
static int dupli_extrude_cursor(bContext *C, wmOperator *op, wmEvent *event) { ViewContext vc; EditVert *eve; float min[3], max[3]; int done= 0; short use_proj; em_setup_viewcontext(C, &vc); use_proj= (vc.scene->toolsettings->snap_flag & SCE_SNAP) && (vc.scene->toolsettings->snap_mode==SCE_SNAP_MODE_FACE); invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); INIT_MINMAX(min, max); for(eve= vc.em->verts.first; eve; eve= eve->next) { if(eve->f & SELECT) { DO_MINMAX(eve->co, min, max); done= 1; } } /* call extrude? */ if(done) { const short rot_src= RNA_boolean_get(op->ptr, "rotate_source"); EditEdge *eed; float vec[3], cent[3], mat[3][3]; float nor[3]= {0.0, 0.0, 0.0}; /* 2D normal calc */ float mval_f[2]; mval_f[0]= (float)event->mval[0]; mval_f[1]= (float)event->mval[1]; done= 0; /* calculate the normal for selected edges */ for(eed= vc.em->edges.first; eed; eed= eed->next) { if(eed->f & SELECT) { float co1[3], co2[3]; mul_v3_m4v3(co1, vc.obedit->obmat, eed->v1->co); mul_v3_m4v3(co2, vc.obedit->obmat, eed->v2->co); project_float_noclip(vc.ar, co1, co1); project_float_noclip(vc.ar, co2, co2); /* 2D rotate by 90d while adding. * (x, y) = (y, -x) * * accumulate the screenspace normal in 2D, * with screenspace edge length weighting the result. */ if(line_point_side_v2(co1, co2, mval_f) >= 0.0f) { nor[0] += (co1[1] - co2[1]); nor[1] += -(co1[0] - co2[0]); } else { nor[0] += (co2[1] - co1[1]); nor[1] += -(co2[0] - co1[0]); } done= 1; } } if(done) { float view_vec[3], cross[3]; /* convert the 2D nomal into 3D */ mul_mat3_m4_v3(vc.rv3d->viewinv, nor); /* worldspace */ mul_mat3_m4_v3(vc.obedit->imat, nor); /* local space */ /* correct the normal to be aligned on the view plane */ copy_v3_v3(view_vec, vc.rv3d->viewinv[2]); mul_mat3_m4_v3(vc.obedit->imat, view_vec); cross_v3_v3v3(cross, nor, view_vec); cross_v3_v3v3(nor, view_vec, cross); normalize_v3(nor); } /* center */ mid_v3_v3v3(cent, min, max); copy_v3_v3(min, cent); mul_m4_v3(vc.obedit->obmat, min); // view space view3d_get_view_aligned_coordinate(&vc, min, event->mval, TRUE); mul_m4_v3(vc.obedit->imat, min); // back in object space sub_v3_v3(min, cent); /* calculate rotation */ unit_m3(mat); if(done) { float dot; copy_v3_v3(vec, min); normalize_v3(vec); dot= dot_v3v3(vec, nor); if( fabs(dot)<0.999) { float cross[3], si, q1[4]; cross_v3_v3v3(cross, nor, vec); normalize_v3(cross); dot= 0.5f*saacos(dot); /* halve the rotation if its applied twice */ if(rot_src) dot *= 0.5f; si= (float)sin(dot); q1[0]= (float)cos(dot); q1[1]= cross[0]*si; q1[2]= cross[1]*si; q1[3]= cross[2]*si; quat_to_mat3( mat,q1); } } if(rot_src) { rotateflag(vc.em, SELECT, cent, mat); /* also project the source, for retopo workflow */ if(use_proj) EM_project_snap_verts(C, vc.ar, vc.obedit, vc.em); } extrudeflag(vc.obedit, vc.em, SELECT, nor, 0); rotateflag(vc.em, SELECT, cent, mat); translateflag(vc.em, SELECT, min); recalc_editnormals(vc.em); } else if(vc.em->selectmode & SCE_SELECT_VERTEX) { float imat[4][4]; const float *curs= give_cursor(vc.scene, vc.v3d); copy_v3_v3(min, curs); view3d_get_view_aligned_coordinate(&vc, min, event->mval, TRUE); eve= addvertlist(vc.em, 0, NULL); invert_m4_m4(imat, vc.obedit->obmat); mul_v3_m4v3(eve->co, imat, min); eve->f= SELECT; } if(use_proj) EM_project_snap_verts(C, vc.ar, vc.obedit, vc.em); WM_event_add_notifier(C, NC_GEOM|ND_DATA, vc.obedit->data); DAG_id_tag_update(vc.obedit->data, 0); return OPERATOR_FINISHED; }
/* mode: 1 = proportional, 2 = all joints (for bones only) */ static void make_trans_verts(Object *obedit, float *min, float *max, int mode) { Nurb *nu; BezTriple *bezt; BPoint *bp; TransVert *tv=NULL; MetaElem *ml; EditVert *eve; EditBone *ebo; float total, center[3], centroid[3]; int a; tottrans= 0; // global! INIT_MINMAX(min, max); centroid[0]=centroid[1]=centroid[2]= 0.0; if(obedit->type==OB_MESH) { Mesh *me= obedit->data; EditMesh *em= me->edit_mesh; int proptrans= 0; // transform now requires awareness for select mode, so we tag the f1 flags in verts tottrans= 0; if(em->selectmode & SCE_SELECT_VERTEX) { for(eve= em->verts.first; eve; eve= eve->next) { if(eve->h==0 && (eve->f & SELECT)) { eve->f1= SELECT; tottrans++; } else eve->f1= 0; } } else if(em->selectmode & SCE_SELECT_EDGE) { EditEdge *eed; for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; for(eed= em->edges.first; eed; eed= eed->next) { if(eed->h==0 && (eed->f & SELECT)) eed->v1->f1= eed->v2->f1= SELECT; } for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++; } else { EditFace *efa; for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; for(efa= em->faces.first; efa; efa= efa->next) { if(efa->h==0 && (efa->f & SELECT)) { efa->v1->f1= efa->v2->f1= efa->v3->f1= SELECT; if(efa->v4) efa->v4->f1= SELECT; } } for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++; } /* proportional edit exception... */ if((mode & 1) && tottrans) { for(eve= em->verts.first; eve; eve= eve->next) { if(eve->h==0) { eve->f1 |= 2; proptrans++; } } if(proptrans>tottrans) tottrans= proptrans; } /* and now make transverts */ if(tottrans) { tv=transvmain= MEM_callocN(tottrans*sizeof(TransVert), "maketransverts"); for(eve= em->verts.first; eve; eve= eve->next) { if(eve->f1) { VECCOPY(tv->oldloc, eve->co); tv->loc= eve->co; if(eve->no[0]!=0.0 || eve->no[1]!=0.0 ||eve->no[2]!=0.0) tv->nor= eve->no; // note this is a hackish signal (ton) tv->flag= eve->f1 & SELECT; tv++; } } } } else if (obedit->type==OB_ARMATURE){ bArmature *arm= obedit->data; int totmalloc= BLI_countlist(arm->edbo); tv=transvmain= MEM_callocN(totmalloc*sizeof(TransVert), "maketransverts armature"); for (ebo= arm->edbo->first; ebo; ebo=ebo->next){ if(ebo->layer & arm->layer) { short tipsel= (ebo->flag & BONE_TIPSEL); short rootsel= (ebo->flag & BONE_ROOTSEL); short rootok= (!(ebo->parent && (ebo->flag & BONE_CONNECTED) && ebo->parent->flag & BONE_TIPSEL)); if ((tipsel && rootsel) || (rootsel)) { /* Don't add the tip (unless mode & 2, for getting all joints), * otherwise we get zero-length bones as tips will snap to the same * location as heads. */ if (rootok) { VECCOPY (tv->oldloc, ebo->head); tv->loc= ebo->head; tv->nor= NULL; tv->flag= 1; tv++; tottrans++; } if ((mode & 2) && (tipsel)) { VECCOPY (tv->oldloc, ebo->tail); tv->loc= ebo->tail; tv->nor= NULL; tv->flag= 1; tv++; tottrans++; } } else if (tipsel) { VECCOPY (tv->oldloc, ebo->tail); tv->loc= ebo->tail; tv->nor= NULL; tv->flag= 1; tv++; tottrans++; } } } } else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) { Curve *cu= obedit->data; int totmalloc= 0; for(nu= cu->editnurb->first; nu; nu= nu->next) { if(nu->type == CU_BEZIER) totmalloc += 3*nu->pntsu; else totmalloc += nu->pntsu*nu->pntsv; } tv=transvmain= MEM_callocN(totmalloc*sizeof(TransVert), "maketransverts curve"); nu= cu->editnurb->first; while(nu) { if(nu->type == CU_BEZIER) { a= nu->pntsu; bezt= nu->bezt; while(a--) { if(bezt->hide==0) { if((mode & 1) || (bezt->f1 & SELECT)) { VECCOPY(tv->oldloc, bezt->vec[0]); tv->loc= bezt->vec[0]; tv->flag= bezt->f1 & SELECT; tv++; tottrans++; } if((mode & 1) || (bezt->f2 & SELECT)) { VECCOPY(tv->oldloc, bezt->vec[1]); tv->loc= bezt->vec[1]; tv->val= &(bezt->alfa); tv->oldval= bezt->alfa; tv->flag= bezt->f2 & SELECT; tv++; tottrans++; } if((mode & 1) || (bezt->f3 & SELECT)) { VECCOPY(tv->oldloc, bezt->vec[2]); tv->loc= bezt->vec[2]; tv->flag= bezt->f3 & SELECT; tv++; tottrans++; } } bezt++; } } else { a= nu->pntsu*nu->pntsv; bp= nu->bp; while(a--) { if(bp->hide==0) { if((mode & 1) || (bp->f1 & SELECT)) { VECCOPY(tv->oldloc, bp->vec); tv->loc= bp->vec; tv->val= &(bp->alfa); tv->oldval= bp->alfa; tv->flag= bp->f1 & SELECT; tv++; tottrans++; } } bp++; } } nu= nu->next; } } else if(obedit->type==OB_MBALL) { MetaBall *mb= obedit->data; int totmalloc= BLI_countlist(mb->editelems); tv=transvmain= MEM_callocN(totmalloc*sizeof(TransVert), "maketransverts mball"); ml= mb->editelems->first; while(ml) { if(ml->flag & SELECT) { tv->loc= &ml->x; VECCOPY(tv->oldloc, tv->loc); tv->val= &(ml->rad); tv->oldval= ml->rad; tv->flag= 1; tv++; tottrans++; } ml= ml->next; } } else if(obedit->type==OB_LATTICE) { Lattice *lt= obedit->data; bp= lt->editlatt->def; a= lt->editlatt->pntsu*lt->editlatt->pntsv*lt->editlatt->pntsw; tv=transvmain= MEM_callocN(a*sizeof(TransVert), "maketransverts curve"); while(a--) { if((mode & 1) || (bp->f1 & SELECT)) { if(bp->hide==0) { VECCOPY(tv->oldloc, bp->vec); tv->loc= bp->vec; tv->flag= bp->f1 & SELECT; tv++; tottrans++; } } bp++; } } /* cent etc */ tv= transvmain; total= 0.0; for(a=0; a<tottrans; a++, tv++) { if(tv->flag & SELECT) { centroid[0]+= tv->oldloc[0]; centroid[1]+= tv->oldloc[1]; centroid[2]+= tv->oldloc[2]; total+= 1.0; DO_MINMAX(tv->oldloc, min, max); } } if(total!=0.0) { centroid[0]/= total; centroid[1]/= total; centroid[2]/= total; } center[0]= (min[0]+max[0])/2.0; center[1]= (min[1]+max[1])/2.0; center[2]= (min[2]+max[2])/2.0; }
/** * Iterates over ALL objects in the scene and all of its sets, including * making all duplis(not only metas). Copies metas to mainb array. * Computes bounding boxes for building BVH. */ static void init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scene, Object *ob) { Scene *sce_iter = scene; Base *base; Object *bob; MetaBall *mb; const MetaElem *ml; float obinv[4][4], obmat[4][4]; unsigned int i; int obnr, zero_size = 0; char obname[MAX_ID_NAME]; SceneBaseIter iter; copy_m4_m4(obmat, ob->obmat); /* to cope with duplicators from BKE_scene_base_iter_next */ invert_m4_m4(obinv, ob->obmat); BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); /* make main array */ BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL); while (BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 1, &base, &bob)) { if (bob->type == OB_MBALL) { zero_size = 0; ml = NULL; if (bob == ob && (base->flag & OB_FROMDUPLI) == 0) { mb = ob->data; if (mb->editelems) ml = mb->editelems->first; else ml = mb->elems.first; } else { char name[MAX_ID_NAME]; int nr; BLI_split_name_num(name, &nr, bob->id.name + 2, '.'); if (STREQ(obname, name)) { mb = bob->data; if (mb->editelems) ml = mb->editelems->first; else ml = mb->elems.first; } } /* when metaball object has zero scale, then MetaElem to this MetaBall * will not be put to mainb array */ if (has_zero_axis_m4(bob->obmat)) { zero_size = 1; } else if (bob->parent) { struct Object *pob = bob->parent; while (pob) { if (has_zero_axis_m4(pob->obmat)) { zero_size = 1; break; } pob = pob->parent; } } if (zero_size) { while (ml) { ml = ml->next; } } else { while (ml) { if (!(ml->flag & MB_HIDE)) { float pos[4][4], rot[4][4]; float expx, expy, expz; float tempmin[3], tempmax[3]; MetaElem *new_ml; /* make a copy because of duplicates */ new_ml = BLI_memarena_alloc(process->pgn_elements, sizeof(MetaElem)); *(new_ml) = *ml; new_ml->bb = BLI_memarena_alloc(process->pgn_elements, sizeof(BoundBox)); new_ml->mat = BLI_memarena_alloc(process->pgn_elements, 4 * 4 * sizeof(float)); new_ml->imat = BLI_memarena_alloc(process->pgn_elements, 4 * 4 * sizeof(float)); /* too big stiffness seems only ugly due to linear interpolation * no need to have possibility for too big stiffness */ if (ml->s > 10.0f) new_ml->s = 10.0f; else new_ml->s = ml->s; /* if metaball is negative, set stiffness negative */ if (new_ml->flag & MB_NEGATIVE) new_ml->s = -new_ml->s; /* Translation of MetaElem */ unit_m4(pos); pos[3][0] = ml->x; pos[3][1] = ml->y; pos[3][2] = ml->z; /* Rotation of MetaElem is stored in quat */ quat_to_mat4(rot, ml->quat); /* basis object space -> world -> ml object space -> position -> rotation -> ml local space */ mul_m4_series((float(*)[4])new_ml->mat, obinv, bob->obmat, pos, rot); /* ml local space -> basis object space */ invert_m4_m4((float(*)[4])new_ml->imat, (float(*)[4])new_ml->mat); /* rad2 is inverse of squared radius */ new_ml->rad2 = 1 / (ml->rad * ml->rad); /* initial dimensions = radius */ expx = ml->rad; expy = ml->rad; expz = ml->rad; switch (ml->type) { case MB_BALL: break; case MB_CUBE: /* cube is "expanded" by expz, expy and expx */ expz += ml->expz; /* fall through */ case MB_PLANE: /* plane is "expanded" by expy and expx */ expy += ml->expy; /* fall through */ case MB_TUBE: /* tube is "expanded" by expx */ expx += ml->expx; break; case MB_ELIPSOID: /* ellipsoid is "stretched" by exp* */ expx *= ml->expx; expy *= ml->expy; expz *= ml->expz; break; } /* untransformed Bounding Box of MetaElem */ /* TODO, its possible the elem type has been changed and the exp* values can use a fallback */ copy_v3_fl3(new_ml->bb->vec[0], -expx, -expy, -expz); /* 0 */ copy_v3_fl3(new_ml->bb->vec[1], +expx, -expy, -expz); /* 1 */ copy_v3_fl3(new_ml->bb->vec[2], +expx, +expy, -expz); /* 2 */ copy_v3_fl3(new_ml->bb->vec[3], -expx, +expy, -expz); /* 3 */ copy_v3_fl3(new_ml->bb->vec[4], -expx, -expy, +expz); /* 4 */ copy_v3_fl3(new_ml->bb->vec[5], +expx, -expy, +expz); /* 5 */ copy_v3_fl3(new_ml->bb->vec[6], +expx, +expy, +expz); /* 6 */ copy_v3_fl3(new_ml->bb->vec[7], -expx, +expy, +expz); /* 7 */ /* transformation of Metalem bb */ for (i = 0; i < 8; i++) mul_m4_v3((float(*)[4])new_ml->mat, new_ml->bb->vec[i]); /* find max and min of transformed bb */ INIT_MINMAX(tempmin, tempmax); for (i = 0; i < 8; i++) { DO_MINMAX(new_ml->bb->vec[i], tempmin, tempmax); } /* set only point 0 and 6 - AABB of Metaelem */ copy_v3_v3(new_ml->bb->vec[0], tempmin); copy_v3_v3(new_ml->bb->vec[6], tempmax); /* add new_ml to mainb[] */ if (UNLIKELY(process->totelem == process->mem)) { process->mem = process->mem * 2 + 10; process->mainb = MEM_reallocN(process->mainb, sizeof(MetaElem *) * process->mem); } process->mainb[process->totelem++] = new_ml; } ml = ml->next; } } } } /* compute AABB of all Metaelems */ if (process->totelem > 0) { copy_v3_v3(process->allbb.min, process->mainb[0]->bb->vec[0]); copy_v3_v3(process->allbb.max, process->mainb[0]->bb->vec[6]); for (i = 1; i < process->totelem; i++) make_box_union(process->mainb[i]->bb, &process->allbb, &process->allbb); } }
void curve_deform_verts(Scene *scene, Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3], int numVerts, char *vgroup, short defaxis) { Curve *cu; int a, flag; CurveDeform cd; int use_vgroups; if(cuOb->type != OB_CURVE) return; cu = cuOb->data; flag = cu->flag; cu->flag |= (CU_PATH|CU_FOLLOW); // needed for path & bevlist init_curve_deform(cuOb, target, &cd, (cu->flag & CU_STRETCH)==0); /* dummy bounds, keep if CU_DEFORM_BOUNDS_OFF is set */ if(defaxis < 3) { cd.dmin[0]= cd.dmin[1]= cd.dmin[2]= 0.0f; cd.dmax[0]= cd.dmax[1]= cd.dmax[2]= 1.0f; } else { /* negative, these bounds give a good rest position */ cd.dmin[0]= cd.dmin[1]= cd.dmin[2]= -1.0f; cd.dmax[0]= cd.dmax[1]= cd.dmax[2]= 0.0f; } /* check whether to use vertex groups (only possible if target is a Mesh) * we want either a Mesh with no derived data, or derived data with * deformverts */ if(target && target->type==OB_MESH) { /* if there's derived data without deformverts, don't use vgroups */ if(dm && !dm->getVertData(dm, 0, CD_MDEFORMVERT)) use_vgroups = 0; else use_vgroups = 1; } else use_vgroups = 0; if(vgroup && vgroup[0] && use_vgroups) { Mesh *me= target->data; int index= defgroup_name_index(target, vgroup); if(index != -1 && (me->dvert || dm)) { MDeformVert *dvert = me->dvert; float vec[3]; float weight; if(cu->flag & CU_DEFORM_BOUNDS_OFF) { /* dummy bounds */ cd.dmin[0]= cd.dmin[1]= cd.dmin[2]= 0.0f; cd.dmax[0]= cd.dmax[1]= cd.dmax[2]= 1.0f; dvert = me->dvert; for(a = 0; a < numVerts; a++, dvert++) { if(dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT); weight= defvert_find_weight(dvert, index); if(weight > 0.0f) { mul_m4_v3(cd.curvespace, vertexCos[a]); copy_v3_v3(vec, vertexCos[a]); calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL); interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight); mul_m4_v3(cd.objectspace, vertexCos[a]); } } } else { /* set mesh min/max bounds */ INIT_MINMAX(cd.dmin, cd.dmax); for(a = 0; a < numVerts; a++, dvert++) { if(dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT); if(defvert_find_weight(dvert, index) > 0.0f) { mul_m4_v3(cd.curvespace, vertexCos[a]); DO_MINMAX(vertexCos[a], cd.dmin, cd.dmax); } } dvert = me->dvert; for(a = 0; a < numVerts; a++, dvert++) { if(dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT); weight= defvert_find_weight(dvert, index); if(weight > 0.0f) { copy_v3_v3(vec, vertexCos[a]); calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL); interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight); mul_m4_v3(cd.objectspace, vertexCos[a]); } } } } } else { if(cu->flag & CU_DEFORM_BOUNDS_OFF) { for(a = 0; a < numVerts; a++) { mul_m4_v3(cd.curvespace, vertexCos[a]); calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL); mul_m4_v3(cd.objectspace, vertexCos[a]); } } else { /* set mesh min max bounds */ INIT_MINMAX(cd.dmin, cd.dmax); for(a = 0; a < numVerts; a++) { mul_m4_v3(cd.curvespace, vertexCos[a]); DO_MINMAX(vertexCos[a], cd.dmin, cd.dmax); } for(a = 0; a < numVerts; a++) { calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL); mul_m4_v3(cd.objectspace, vertexCos[a]); } } } cu->flag = flag; }