/* \brief copy some properties from object to other metaball object with same base name * * When some properties (wiresize, threshold, update flags) of metaball are changed, then this properties * are copied to all metaballs in same "group" (metaballs with same base name: MBall, * MBall.001, MBall.002, etc). The most important is to copy properties to the base metaball, * because this metaball influence polygonisation of metaballs. */ void BKE_mball_properties_copy(Scene *scene, Object *active_object) { Scene *sce_iter = scene; Base *base; Object *ob; MetaBall *active_mball = (MetaBall *)active_object->data; int basisnr, obnr; char basisname[MAX_ID_NAME], obname[MAX_ID_NAME]; SceneBaseIter iter; EvaluationContext *eval_ctx = G.main->eval_ctx; BLI_split_name_num(basisname, &basisnr, active_object->id.name + 2, '.'); 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, &ob)) { if (ob->type == OB_MBALL) { if (ob != active_object) { BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); /* Object ob has to be in same "group" ... it means, that it has to have * same base of its name */ if (STREQ(obname, basisname)) { MetaBall *mb = ob->data; /* Copy properties from selected/edited metaball */ mb->wiresize = active_mball->wiresize; mb->rendersize = active_mball->rendersize; mb->thresh = active_mball->thresh; mb->flag = active_mball->flag; } } } } }
/** \brief This function finds basic MetaBall. * * Basic MetaBall doesn't include any number at the end of * its name. All MetaBalls with same base of name can be * blended. MetaBalls with different basic name can't be * blended. * * warning!, is_basis_mball() can fail on returned object, see long note above. */ Object *BKE_mball_basis_find(Scene *scene, Object *basis) { Scene *sce_iter = scene; Base *base; Object *ob, *bob = basis; int basisnr, obnr; char basisname[MAX_ID_NAME], obname[MAX_ID_NAME]; SceneBaseIter iter; EvaluationContext *eval_ctx = G.main->eval_ctx; BLI_split_name_num(basisname, &basisnr, basis->id.name + 2, '.'); 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, &ob)) { if ((ob->type == OB_MBALL) && !(base->flag & OB_FROMDUPLI)) { if (ob != bob) { BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); /* object ob has to be in same "group" ... it means, that it has to have same base of its name */ if (STREQ(obname, basisname)) { if (obnr < basisnr) { basis = ob; basisnr = obnr; } } } } } return basis; }
/** * 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); } }