/** \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; }
/* \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; } } } } }
/* return nonzero if ob1 is a basis mball for ob */ bool BKE_mball_is_basis_for(Object *ob1, Object *ob2) { int basis1nr, basis2nr; char basis1name[MAX_ID_NAME], basis2name[MAX_ID_NAME]; BLI_split_name_num(basis1name, &basis1nr, ob1->id.name + 2, '.'); BLI_split_name_num(basis2name, &basis2nr, ob2->id.name + 2, '.'); if (STREQ(basis1name, basis2name)) { return BKE_mball_is_basis(ob1); } else { return false; } }
int BLI_uniquename_cb(int (*unique_check)(void *, const char *), void *arg, const char defname[], char delim, char *name, short name_len) { if(name[0] == '\0') { BLI_strncpy(name, defname, name_len); } if(unique_check(arg, name)) { char tempname[UNIQUE_NAME_MAX]; char left[UNIQUE_NAME_MAX]; int number; int len= BLI_split_name_num(left, &number, name, delim); do { int newlen= BLI_snprintf(tempname, name_len, "%s%c%03d", left, delim, ++number); if(newlen >= name_len) { len -= ((newlen + 1) - name_len); if(len < 0) len= number= 0; left[len]= '\0'; } } while(unique_check(arg, tempname)); BLI_strncpy(name, tempname, name_len); return 1; } return 0; }
int BLI_uniquename_cb(int (*unique_check)(void *, const char *), void *arg, const char defname[], char delim, char *name, short name_len) { if (name[0] == '\0') { BLI_strncpy(name, defname, name_len); } if (unique_check(arg, name)) { char numstr[16]; char tempname[UNIQUE_NAME_MAX]; char left[UNIQUE_NAME_MAX]; int number; int len = BLI_split_name_num(left, &number, name, delim); do { int numlen = BLI_snprintf(numstr, sizeof(numstr), "%c%03d", delim, ++number); /* highly unlikely the string only has enough room for the number * but support anyway */ if ((len == 0) || (numlen >= name_len)) { /* number is know not to be utf-8 */ BLI_strncpy(tempname, numstr, name_len); } else { char *tempname_buf; tempname[0] = '\0'; tempname_buf = BLI_strncat_utf8(tempname, left, name_len - numlen); memcpy(tempname_buf, numstr, numlen + 1); } } while (unique_check(arg, tempname)); BLI_strncpy(name, tempname, name_len); return 1; } return 0; }
static int check_for_dupid(ListBase *lb, ID *id, char *name) { ID *idtest; int nr= 0, nrtest, a, left_len; char left[32], leftest[32], in_use[32]; /* make sure input name is terminated properly */ /* if( strlen(name) > 21 ) name[21]= 0; */ /* removed since this is only ever called from one place - campbell */ while (1) { /* phase 1: id already exists? */ idtest = is_dupid(lb, id, name); /* if there is no double, done */ if( idtest == NULL ) return 0; /* we have a dup; need to make a new name */ /* quick check so we can reuse one of first 32 ids if vacant */ memset(in_use, 0, sizeof(in_use)); /* get name portion, number portion ("name.number") */ left_len= BLI_split_name_num(left, &nr, name, '.'); /* if new name will be too long, truncate it */ if(nr > 999 && left_len > 16) { left[16]= 0; left_len= 16; } else if(left_len > 17) { left[17]= 0; left_len= 17; } for(idtest= lb->first; idtest; idtest= idtest->next) { if( (id != idtest) && (idtest->lib == NULL) && (*name == *(idtest->name+2)) && (strncmp(name, idtest->name+2, left_len)==0) && (BLI_split_name_num(leftest, &nrtest, idtest->name+2, '.') == left_len) ) { if(nrtest < sizeof(in_use)) in_use[nrtest]= 1; /* mark as used */ if(nr <= nrtest) nr= nrtest+1; /* track largest unused */ } } /* decide which value of nr to use */ for(a=0; a < sizeof(in_use); a++) { if(a>=nr) break; /* stop when we've check up to biggest */ if( in_use[a]==0 ) { /* found an unused value */ nr = a; break; } } /* If the original name has no numeric suffix, * rather than just chopping and adding numbers, * shave off the end chars until we have a unique name. * Check the null terminators match as well so we dont get Cube.000 -> Cube.00 */ if (nr==0 && name[left_len]== '\0') { int len = left_len-1; idtest= is_dupid(lb, id, name); while (idtest && len> 1) { name[len--] = '\0'; idtest= is_dupid(lb, id, name); } if (idtest == NULL) return 1; /* otherwise just continue and use a number suffix */ } if(nr > 999 && left_len > 16) { /* this would overflow name buffer */ left[16] = 0; /* left_len = 16; */ /* for now this isnt used again */ memcpy(name, left, sizeof(char) * 17); continue; } /* this format specifier is from hell... */ BLI_snprintf(name, sizeof(id->name) - 2,"%s.%.3d", left, nr); return 1; } }
static bool check_for_dupid(ListBase *lb, ID *id, char *name) { ID *idtest; int nr = 0, a, left_len; #define MAX_IN_USE 64 bool in_use[MAX_IN_USE]; /* to speed up finding unused numbers within [1 .. MAX_IN_USE - 1] */ char left[MAX_ID_NAME + 8], leftest[MAX_ID_NAME + 8]; while (true) { /* phase 1: id already exists? */ idtest = is_dupid(lb, id, name); /* if there is no double, done */ if (idtest == NULL) return false; /* we have a dup; need to make a new name */ /* quick check so we can reuse one of first MAX_IN_USE - 1 ids if vacant */ memset(in_use, false, sizeof(in_use)); /* get name portion, number portion ("name.number") */ left_len = BLI_split_name_num(left, &nr, name, '.'); /* if new name will be too long, truncate it */ if (nr > 999 && left_len > (MAX_ID_NAME - 8)) { /* assumption: won't go beyond 9999 */ left[MAX_ID_NAME - 8] = 0; left_len = MAX_ID_NAME - 8; } else if (left_len > (MAX_ID_NAME - 7)) { left[MAX_ID_NAME - 7] = 0; left_len = MAX_ID_NAME - 7; } for (idtest = lb->first; idtest; idtest = idtest->next) { int nrtest; if ( (id != idtest) && (idtest->lib == NULL) && (*name == *(idtest->name + 2)) && (strncmp(name, idtest->name + 2, left_len) == 0) && (BLI_split_name_num(leftest, &nrtest, idtest->name + 2, '.') == left_len) ) { /* will get here at least once, otherwise is_dupid call above would have returned NULL */ if (nrtest < MAX_IN_USE) in_use[nrtest] = true; /* mark as used */ if (nr <= nrtest) nr = nrtest + 1; /* track largest unused */ } } /* At this point, 'nr' will typically be at least 1. (but not always) */ // BLI_assert(nr >= 1); /* decide which value of nr to use */ for (a = 0; a < MAX_IN_USE; a++) { if (a >= nr) break; /* stop when we've checked up to biggest */ /* redundant check */ if (!in_use[a]) { /* found an unused value */ nr = a; /* can only be zero if all potential duplicate names had * nonzero numeric suffixes, which means name itself has * nonzero numeric suffix (else no name conflict and wouldn't * have got here), which means name[left_len] is not a null */ break; } } /* At this point, nr is either the lowest unused number within [0 .. MAX_IN_USE - 1], * or 1 greater than the largest used number if all those low ones are taken. * We can't be bothered to look for the lowest unused number beyond (MAX_IN_USE - 1). */ /* If the original name has no numeric suffix, * rather than just chopping and adding numbers, * shave off the end chars until we have a unique name. * Check the null terminators match as well so we don't get Cube.000 -> Cube.00 */ if (nr == 0 && name[left_len] == '\0') { int len; /* FIXME: this code will never be executed, because either nr will be * at least 1, or name will not end at left_len! */ BLI_assert(0); len = left_len - 1; idtest = is_dupid(lb, id, name); while (idtest && len > 1) { name[len--] = '\0'; idtest = is_dupid(lb, id, name); } if (idtest == NULL) return true; /* otherwise just continue and use a number suffix */ } if (nr > 999 && left_len > (MAX_ID_NAME - 8)) { /* this would overflow name buffer */ left[MAX_ID_NAME - 8] = 0; /* left_len = MAX_ID_NAME - 8; */ /* for now this isn't used again */ memcpy(name, left, sizeof(char) * (MAX_ID_NAME - 7)); continue; } /* this format specifier is from hell... */ BLI_snprintf(name, sizeof(id->name) - 2, "%s.%.3d", left, nr); return true; } #undef MAX_IN_USE }
/** * 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); } }