1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  * MetaBalls are created from a single Object (with a name without number in it),
19  * here the DispList and BoundBox also is located.
20  * All objects with the same name (but with a number in it) are added to this.
21  *
22  * texture coordinates are patched within the displist
23  */
24 
25 /** \file
26  * \ingroup bke
27  */
28 
29 #include <ctype.h>
30 #include <float.h>
31 #include <math.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 
36 #include "MEM_guardedalloc.h"
37 
38 /* Allow using deprecated functionality for .blend file I/O. */
39 #define DNA_DEPRECATED_ALLOW
40 
41 #include "DNA_defaults.h"
42 #include "DNA_material_types.h"
43 #include "DNA_meta_types.h"
44 #include "DNA_object_types.h"
45 #include "DNA_scene_types.h"
46 
47 #include "BLI_blenlib.h"
48 #include "BLI_math.h"
49 #include "BLI_string_utils.h"
50 #include "BLI_utildefines.h"
51 
52 #include "BLT_translation.h"
53 
54 #include "BKE_main.h"
55 
56 #include "BKE_anim_data.h"
57 #include "BKE_curve.h"
58 #include "BKE_displist.h"
59 #include "BKE_idtype.h"
60 #include "BKE_lib_id.h"
61 #include "BKE_lib_query.h"
62 #include "BKE_material.h"
63 #include "BKE_mball.h"
64 #include "BKE_object.h"
65 #include "BKE_scene.h"
66 
67 #include "DEG_depsgraph.h"
68 
69 #include "BLO_read_write.h"
70 
metaball_init_data(ID * id)71 static void metaball_init_data(ID *id)
72 {
73   MetaBall *metaball = (MetaBall *)id;
74 
75   BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(metaball, id));
76 
77   MEMCPY_STRUCT_AFTER(metaball, DNA_struct_default_get(MetaBall), id);
78 }
79 
metaball_copy_data(Main * UNUSED (bmain),ID * id_dst,const ID * id_src,const int UNUSED (flag))80 static void metaball_copy_data(Main *UNUSED(bmain),
81                                ID *id_dst,
82                                const ID *id_src,
83                                const int UNUSED(flag))
84 {
85   MetaBall *metaball_dst = (MetaBall *)id_dst;
86   const MetaBall *metaball_src = (const MetaBall *)id_src;
87 
88   BLI_duplicatelist(&metaball_dst->elems, &metaball_src->elems);
89 
90   metaball_dst->mat = MEM_dupallocN(metaball_src->mat);
91 
92   metaball_dst->editelems = NULL;
93   metaball_dst->lastelem = NULL;
94   metaball_dst->batch_cache = NULL;
95 }
96 
metaball_free_data(ID * id)97 static void metaball_free_data(ID *id)
98 {
99   MetaBall *metaball = (MetaBall *)id;
100 
101   BKE_mball_batch_cache_free(metaball);
102 
103   MEM_SAFE_FREE(metaball->mat);
104 
105   BLI_freelistN(&metaball->elems);
106   if (metaball->disp.first) {
107     BKE_displist_free(&metaball->disp);
108   }
109 }
110 
metaball_foreach_id(ID * id,LibraryForeachIDData * data)111 static void metaball_foreach_id(ID *id, LibraryForeachIDData *data)
112 {
113   MetaBall *metaball = (MetaBall *)id;
114   for (int i = 0; i < metaball->totcol; i++) {
115     BKE_LIB_FOREACHID_PROCESS(data, metaball->mat[i], IDWALK_CB_USER);
116   }
117 }
118 
metaball_blend_write(BlendWriter * writer,ID * id,const void * id_address)119 static void metaball_blend_write(BlendWriter *writer, ID *id, const void *id_address)
120 {
121   MetaBall *mb = (MetaBall *)id;
122   if (mb->id.us > 0 || BLO_write_is_undo(writer)) {
123     /* Clean up, important in undo case to reduce false detection of changed datablocks. */
124     BLI_listbase_clear(&mb->disp);
125     mb->editelems = NULL;
126     /* Must always be cleared (meta's don't have their own edit-data). */
127     mb->needs_flush_to_id = 0;
128     mb->lastelem = NULL;
129     mb->batch_cache = NULL;
130 
131     /* write LibData */
132     BLO_write_id_struct(writer, MetaBall, id_address, &mb->id);
133     BKE_id_blend_write(writer, &mb->id);
134 
135     /* direct data */
136     BLO_write_pointer_array(writer, mb->totcol, mb->mat);
137     if (mb->adt) {
138       BKE_animdata_blend_write(writer, mb->adt);
139     }
140 
141     LISTBASE_FOREACH (MetaElem *, ml, &mb->elems) {
142       BLO_write_struct(writer, MetaElem, ml);
143     }
144   }
145 }
146 
metaball_blend_read_data(BlendDataReader * reader,ID * id)147 static void metaball_blend_read_data(BlendDataReader *reader, ID *id)
148 {
149   MetaBall *mb = (MetaBall *)id;
150   BLO_read_data_address(reader, &mb->adt);
151   BKE_animdata_blend_read_data(reader, mb->adt);
152 
153   BLO_read_pointer_array(reader, (void **)&mb->mat);
154 
155   BLO_read_list(reader, &(mb->elems));
156 
157   BLI_listbase_clear(&mb->disp);
158   mb->editelems = NULL;
159   /* Must always be cleared (meta's don't have their own edit-data). */
160   mb->needs_flush_to_id = 0;
161   /*  mb->edit_elems.first= mb->edit_elems.last= NULL;*/
162   mb->lastelem = NULL;
163   mb->batch_cache = NULL;
164 }
165 
metaball_blend_read_lib(BlendLibReader * reader,ID * id)166 static void metaball_blend_read_lib(BlendLibReader *reader, ID *id)
167 {
168   MetaBall *mb = (MetaBall *)id;
169   for (int a = 0; a < mb->totcol; a++) {
170     BLO_read_id_address(reader, mb->id.lib, &mb->mat[a]);
171   }
172 
173   BLO_read_id_address(reader, mb->id.lib, &mb->ipo);  // XXX deprecated - old animation system
174 }
175 
metaball_blend_read_expand(BlendExpander * expander,ID * id)176 static void metaball_blend_read_expand(BlendExpander *expander, ID *id)
177 {
178   MetaBall *mb = (MetaBall *)id;
179   for (int a = 0; a < mb->totcol; a++) {
180     BLO_expand(expander, mb->mat[a]);
181   }
182 }
183 
184 IDTypeInfo IDType_ID_MB = {
185     .id_code = ID_MB,
186     .id_filter = FILTER_ID_MB,
187     .main_listbase_index = INDEX_ID_MB,
188     .struct_size = sizeof(MetaBall),
189     .name = "Metaball",
190     .name_plural = "metaballs",
191     .translation_context = BLT_I18NCONTEXT_ID_METABALL,
192     .flags = 0,
193 
194     .init_data = metaball_init_data,
195     .copy_data = metaball_copy_data,
196     .free_data = metaball_free_data,
197     .make_local = NULL,
198     .foreach_id = metaball_foreach_id,
199     .foreach_cache = NULL,
200 
201     .blend_write = metaball_blend_write,
202     .blend_read_data = metaball_blend_read_data,
203     .blend_read_lib = metaball_blend_read_lib,
204     .blend_read_expand = metaball_blend_read_expand,
205 };
206 
207 /* Functions */
208 
BKE_mball_add(Main * bmain,const char * name)209 MetaBall *BKE_mball_add(Main *bmain, const char *name)
210 {
211   MetaBall *mb;
212 
213   mb = BKE_id_new(bmain, ID_MB, name);
214 
215   return mb;
216 }
217 
218 /* most simple meta-element adding function
219  * don't do context manipulation here (rna uses) */
BKE_mball_element_add(MetaBall * mb,const int type)220 MetaElem *BKE_mball_element_add(MetaBall *mb, const int type)
221 {
222   MetaElem *ml = MEM_callocN(sizeof(MetaElem), "metaelem");
223 
224   unit_qt(ml->quat);
225 
226   ml->rad = 2.0;
227   ml->s = 2.0;
228   ml->flag = MB_SCALE_RAD;
229 
230   switch (type) {
231     case MB_BALL:
232       ml->type = MB_BALL;
233       ml->expx = ml->expy = ml->expz = 1.0;
234 
235       break;
236     case MB_TUBE:
237       ml->type = MB_TUBE;
238       ml->expx = ml->expy = ml->expz = 1.0;
239 
240       break;
241     case MB_PLANE:
242       ml->type = MB_PLANE;
243       ml->expx = ml->expy = ml->expz = 1.0;
244 
245       break;
246     case MB_ELIPSOID:
247       ml->type = MB_ELIPSOID;
248       ml->expx = 1.2f;
249       ml->expy = 0.8f;
250       ml->expz = 1.0;
251 
252       break;
253     case MB_CUBE:
254       ml->type = MB_CUBE;
255       ml->expx = ml->expy = ml->expz = 1.0;
256 
257       break;
258     default:
259       break;
260   }
261 
262   BLI_addtail(&mb->elems, ml);
263 
264   return ml;
265 }
266 /**
267  * Compute bounding box of all #MetaElem / #MetaBall
268  *
269  * Bounding box is computed from polygonized surface. \a ob is
270  * basic meta-balls (with name `Meta` for example). All other meta-ball objects
271  * (with names `Meta.001`, `Meta.002`, etc) are included in this bounding-box.
272  */
BKE_mball_texspace_calc(Object * ob)273 void BKE_mball_texspace_calc(Object *ob)
274 {
275   DispList *dl;
276   BoundBox *bb;
277   float *data, min[3], max[3] /*, loc[3], size[3] */;
278   int tot;
279   bool do_it = false;
280 
281   if (ob->runtime.bb == NULL) {
282     ob->runtime.bb = MEM_callocN(sizeof(BoundBox), "mb boundbox");
283   }
284   bb = ob->runtime.bb;
285 
286   /* Weird one, this. */
287   /*      INIT_MINMAX(min, max); */
288   (min)[0] = (min)[1] = (min)[2] = 1.0e30f;
289   (max)[0] = (max)[1] = (max)[2] = -1.0e30f;
290 
291   dl = ob->runtime.curve_cache->disp.first;
292   while (dl) {
293     tot = dl->nr;
294     if (tot) {
295       do_it = true;
296     }
297     data = dl->verts;
298     while (tot--) {
299       /* Also weird... but longer. From utildefines. */
300       minmax_v3v3_v3(min, max, data);
301       data += 3;
302     }
303     dl = dl->next;
304   }
305 
306   if (!do_it) {
307     min[0] = min[1] = min[2] = -1.0f;
308     max[0] = max[1] = max[2] = 1.0f;
309   }
310 
311   BKE_boundbox_init_from_minmax(bb, min, max);
312 
313   bb->flag &= ~BOUNDBOX_DIRTY;
314 }
315 
316 /** Return or compute bbox for given metaball object. */
BKE_mball_boundbox_get(Object * ob)317 BoundBox *BKE_mball_boundbox_get(Object *ob)
318 {
319   BLI_assert(ob->type == OB_MBALL);
320 
321   if (ob->runtime.bb != NULL && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) {
322     return ob->runtime.bb;
323   }
324 
325   /* This should always only be called with evaluated objects,
326    * but currently RNA is a problem here... */
327   if (ob->runtime.curve_cache != NULL) {
328     BKE_mball_texspace_calc(ob);
329   }
330 
331   return ob->runtime.bb;
332 }
333 
BKE_mball_make_orco(Object * ob,ListBase * dispbase)334 float *BKE_mball_make_orco(Object *ob, ListBase *dispbase)
335 {
336   BoundBox *bb;
337   DispList *dl;
338   float *data, *orco, *orcodata;
339   float loc[3], size[3];
340   int a;
341 
342   /* restore size and loc */
343   bb = ob->runtime.bb;
344   loc[0] = (bb->vec[0][0] + bb->vec[4][0]) / 2.0f;
345   size[0] = bb->vec[4][0] - loc[0];
346   loc[1] = (bb->vec[0][1] + bb->vec[2][1]) / 2.0f;
347   size[1] = bb->vec[2][1] - loc[1];
348   loc[2] = (bb->vec[0][2] + bb->vec[1][2]) / 2.0f;
349   size[2] = bb->vec[1][2] - loc[2];
350 
351   dl = dispbase->first;
352   orcodata = MEM_mallocN(sizeof(float[3]) * dl->nr, "MballOrco");
353 
354   data = dl->verts;
355   orco = orcodata;
356   a = dl->nr;
357   while (a--) {
358     orco[0] = (data[0] - loc[0]) / size[0];
359     orco[1] = (data[1] - loc[1]) / size[1];
360     orco[2] = (data[2] - loc[2]) / size[2];
361 
362     data += 3;
363     orco += 3;
364   }
365 
366   return orcodata;
367 }
368 
369 /**
370  * \brief Test, if \a ob is a basis meta-ball.
371  *
372  * It test last character of Object ID name. If last character
373  * is digit it return 0, else it return 1.
374  *
375  *
376  * Meta-Ball Basis Notes from Blender-2.5x
377  * =======================================
378  *
379  * This is a can of worms.
380  *
381  * This really needs a rewrite/refactor its totally broken in anything other than basic cases
382  * Multiple Scenes + Set Scenes & mixing meta-ball basis _should_ work but fails to update the
383  * depsgraph on rename and linking into scenes or removal of basis meta-ball.
384  * So take care when changing this code.
385  *
386  * Main idiot thing here is that the system returns #BKE_mball_basis_find()
387  * objects which fail a #BKE_mball_is_basis() test.
388  *
389  * Not only that but the depsgraph and their areas depend on this behavior,
390  * so making small fixes here isn't worth it.
391  * - Campbell
392  */
BKE_mball_is_basis(Object * ob)393 bool BKE_mball_is_basis(Object *ob)
394 {
395   /* just a quick test */
396   const int len = strlen(ob->id.name);
397   return (!isdigit(ob->id.name[len - 1]));
398 }
399 
400 /* return nonzero if ob1 is a basis mball for ob */
BKE_mball_is_basis_for(Object * ob1,Object * ob2)401 bool BKE_mball_is_basis_for(Object *ob1, Object *ob2)
402 {
403   int basis1nr, basis2nr;
404   char basis1name[MAX_ID_NAME], basis2name[MAX_ID_NAME];
405 
406   if (ob1->id.name[2] != ob2->id.name[2]) {
407     /* Quick return in case first char of both ID's names is not the same... */
408     return false;
409   }
410 
411   BLI_split_name_num(basis1name, &basis1nr, ob1->id.name + 2, '.');
412   BLI_split_name_num(basis2name, &basis2nr, ob2->id.name + 2, '.');
413 
414   if (STREQ(basis1name, basis2name)) {
415     return BKE_mball_is_basis(ob1);
416   }
417 
418   return false;
419 }
420 
BKE_mball_is_any_selected(const MetaBall * mb)421 bool BKE_mball_is_any_selected(const MetaBall *mb)
422 {
423   for (const MetaElem *ml = mb->editelems->first; ml != NULL; ml = ml->next) {
424     if (ml->flag & SELECT) {
425       return true;
426     }
427   }
428   return false;
429 }
430 
BKE_mball_is_any_selected_multi(Base ** bases,int bases_len)431 bool BKE_mball_is_any_selected_multi(Base **bases, int bases_len)
432 {
433   for (uint base_index = 0; base_index < bases_len; base_index++) {
434     Object *obedit = bases[base_index]->object;
435     MetaBall *mb = (MetaBall *)obedit->data;
436     if (BKE_mball_is_any_selected(mb)) {
437       return true;
438     }
439   }
440   return false;
441 }
442 
BKE_mball_is_any_unselected(const MetaBall * mb)443 bool BKE_mball_is_any_unselected(const MetaBall *mb)
444 {
445   for (const MetaElem *ml = mb->editelems->first; ml != NULL; ml = ml->next) {
446     if ((ml->flag & SELECT) == 0) {
447       return true;
448     }
449   }
450   return false;
451 }
452 
453 /**
454  * \brief copy some properties from object to other meta-ball object with same base name
455  *
456  * When some properties (wire-size, threshold, update flags) of meta-ball are changed, then this
457  * properties are copied to all meta-balls in same "group" (meta-balls with same base name:
458  * `MBall`, `MBall.001`, `MBall.002`, etc). The most important is to copy properties to the base
459  * meta-ball, because this meta-ball influence polygonization of meta-balls. */
BKE_mball_properties_copy(Scene * scene,Object * active_object)460 void BKE_mball_properties_copy(Scene *scene, Object *active_object)
461 {
462   Scene *sce_iter = scene;
463   Base *base;
464   Object *ob;
465   MetaBall *active_mball = (MetaBall *)active_object->data;
466   int basisnr, obnr;
467   char basisname[MAX_ID_NAME], obname[MAX_ID_NAME];
468   SceneBaseIter iter;
469 
470   BLI_split_name_num(basisname, &basisnr, active_object->id.name + 2, '.');
471 
472   /* Pass depsgraph as NULL, which means we will not expand into
473    * duplis unlike when we generate the meta-ball. Expanding duplis
474    * would not be compatible when editing multiple view layers. */
475   BKE_scene_base_iter_next(NULL, &iter, &sce_iter, 0, NULL, NULL);
476   while (BKE_scene_base_iter_next(NULL, &iter, &sce_iter, 1, &base, &ob)) {
477     if (ob->type == OB_MBALL) {
478       if (ob != active_object) {
479         BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
480 
481         /* Object ob has to be in same "group" ... it means, that it has to have
482          * same base of its name */
483         if (STREQ(obname, basisname)) {
484           MetaBall *mb = ob->data;
485 
486           /* Copy properties from selected/edited metaball */
487           mb->wiresize = active_mball->wiresize;
488           mb->rendersize = active_mball->rendersize;
489           mb->thresh = active_mball->thresh;
490           mb->flag = active_mball->flag;
491           DEG_id_tag_update(&mb->id, 0);
492         }
493       }
494     }
495   }
496 }
497 
498 /** \brief This function finds the basis MetaBall.
499  *
500  * Basis meta-ball doesn't include any number at the end of
501  * its name. All meta-balls with same base of name can be
502  * blended. meta-balls with different basic name can't be blended.
503  *
504  * \warning #BKE_mball_is_basis() can fail on returned object, see function docs for details.
505  */
BKE_mball_basis_find(Scene * scene,Object * object)506 Object *BKE_mball_basis_find(Scene *scene, Object *object)
507 {
508   Object *bob = object;
509   int basisnr, obnr;
510   char basisname[MAX_ID_NAME], obname[MAX_ID_NAME];
511 
512   BLI_split_name_num(basisname, &basisnr, object->id.name + 2, '.');
513 
514   LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
515     LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
516       Object *ob = base->object;
517       if ((ob->type == OB_MBALL) && !(base->flag & BASE_FROM_DUPLI)) {
518         if (ob != bob) {
519           BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
520 
521           /* Object ob has to be in same "group" ... it means,
522            * that it has to have same base of its name. */
523           if (STREQ(obname, basisname)) {
524             if (obnr < basisnr) {
525               object = ob;
526               basisnr = obnr;
527             }
528           }
529         }
530       }
531     }
532   }
533 
534   return object;
535 }
536 
BKE_mball_minmax_ex(const MetaBall * mb,float min[3],float max[3],const float obmat[4][4],const short flag)537 bool BKE_mball_minmax_ex(
538     const MetaBall *mb, float min[3], float max[3], const float obmat[4][4], const short flag)
539 {
540   const float scale = obmat ? mat4_to_scale(obmat) : 1.0f;
541   bool changed = false;
542   float centroid[3], vec[3];
543 
544   INIT_MINMAX(min, max);
545 
546   LISTBASE_FOREACH (const MetaElem *, ml, &mb->elems) {
547     if ((ml->flag & flag) == flag) {
548       const float scale_mb = (ml->rad * 0.5f) * scale;
549 
550       if (obmat) {
551         mul_v3_m4v3(centroid, obmat, &ml->x);
552       }
553       else {
554         copy_v3_v3(centroid, &ml->x);
555       }
556 
557       /* TODO, non circle shapes cubes etc, probably nobody notices - campbell */
558       for (int i = -1; i != 3; i += 2) {
559         copy_v3_v3(vec, centroid);
560         add_v3_fl(vec, scale_mb * i);
561         minmax_v3v3_v3(min, max, vec);
562       }
563       changed = true;
564     }
565   }
566 
567   return changed;
568 }
569 
570 /* basic vertex data functions */
BKE_mball_minmax(const MetaBall * mb,float min[3],float max[3])571 bool BKE_mball_minmax(const MetaBall *mb, float min[3], float max[3])
572 {
573   INIT_MINMAX(min, max);
574 
575   LISTBASE_FOREACH (const MetaElem *, ml, &mb->elems) {
576     minmax_v3v3_v3(min, max, &ml->x);
577   }
578 
579   return (BLI_listbase_is_empty(&mb->elems) == false);
580 }
581 
BKE_mball_center_median(const MetaBall * mb,float r_cent[3])582 bool BKE_mball_center_median(const MetaBall *mb, float r_cent[3])
583 {
584   int total = 0;
585 
586   zero_v3(r_cent);
587 
588   LISTBASE_FOREACH (const MetaElem *, ml, &mb->elems) {
589     add_v3_v3(r_cent, &ml->x);
590     total++;
591   }
592 
593   if (total) {
594     mul_v3_fl(r_cent, 1.0f / (float)total);
595   }
596 
597   return (total != 0);
598 }
599 
BKE_mball_center_bounds(const MetaBall * mb,float r_cent[3])600 bool BKE_mball_center_bounds(const MetaBall *mb, float r_cent[3])
601 {
602   float min[3], max[3];
603 
604   if (BKE_mball_minmax(mb, min, max)) {
605     mid_v3_v3v3(r_cent, min, max);
606     return true;
607   }
608 
609   return false;
610 }
611 
BKE_mball_transform(MetaBall * mb,const float mat[4][4],const bool do_props)612 void BKE_mball_transform(MetaBall *mb, const float mat[4][4], const bool do_props)
613 {
614   float quat[4];
615   const float scale = mat4_to_scale(mat);
616   const float scale_sqrt = sqrtf(scale);
617 
618   mat4_to_quat(quat, mat);
619 
620   LISTBASE_FOREACH (MetaElem *, ml, &mb->elems) {
621     mul_m4_v3(mat, &ml->x);
622     mul_qt_qtqt(ml->quat, quat, ml->quat);
623 
624     if (do_props) {
625       ml->rad *= scale;
626       /* hrmf, probably elems shouldn't be
627        * treating scale differently - campbell */
628       if (!MB_TYPE_SIZE_SQUARED(ml->type)) {
629         mul_v3_fl(&ml->expx, scale);
630       }
631       else {
632         mul_v3_fl(&ml->expx, scale_sqrt);
633       }
634     }
635   }
636 }
637 
BKE_mball_translate(MetaBall * mb,const float offset[3])638 void BKE_mball_translate(MetaBall *mb, const float offset[3])
639 {
640   LISTBASE_FOREACH (MetaElem *, ml, &mb->elems) {
641     add_v3_v3(&ml->x, offset);
642   }
643 }
644 
645 /* *** select funcs *** */
BKE_mball_select_count(const MetaBall * mb)646 int BKE_mball_select_count(const MetaBall *mb)
647 {
648   int sel = 0;
649   LISTBASE_FOREACH (const MetaElem *, ml, mb->editelems) {
650     if (ml->flag & SELECT) {
651       sel++;
652     }
653   }
654   return sel;
655 }
656 
BKE_mball_select_count_multi(Base ** bases,int bases_len)657 int BKE_mball_select_count_multi(Base **bases, int bases_len)
658 {
659   int sel = 0;
660   for (uint ob_index = 0; ob_index < bases_len; ob_index++) {
661     const Object *obedit = bases[ob_index]->object;
662     const MetaBall *mb = (MetaBall *)obedit->data;
663     sel += BKE_mball_select_count(mb);
664   }
665   return sel;
666 }
667 
BKE_mball_select_all(MetaBall * mb)668 bool BKE_mball_select_all(MetaBall *mb)
669 {
670   bool changed = false;
671   LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) {
672     if ((ml->flag & SELECT) == 0) {
673       ml->flag |= SELECT;
674       changed = true;
675     }
676   }
677   return changed;
678 }
679 
BKE_mball_select_all_multi_ex(Base ** bases,int bases_len)680 bool BKE_mball_select_all_multi_ex(Base **bases, int bases_len)
681 {
682   bool changed_multi = false;
683   for (uint ob_index = 0; ob_index < bases_len; ob_index++) {
684     Object *obedit = bases[ob_index]->object;
685     MetaBall *mb = obedit->data;
686     changed_multi |= BKE_mball_select_all(mb);
687   }
688   return changed_multi;
689 }
690 
BKE_mball_deselect_all(MetaBall * mb)691 bool BKE_mball_deselect_all(MetaBall *mb)
692 {
693   bool changed = false;
694   LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) {
695     if ((ml->flag & SELECT) != 0) {
696       ml->flag &= ~SELECT;
697       changed = true;
698     }
699   }
700   return changed;
701 }
702 
BKE_mball_deselect_all_multi_ex(Base ** bases,int bases_len)703 bool BKE_mball_deselect_all_multi_ex(Base **bases, int bases_len)
704 {
705   bool changed_multi = false;
706   for (uint ob_index = 0; ob_index < bases_len; ob_index++) {
707     Object *obedit = bases[ob_index]->object;
708     MetaBall *mb = obedit->data;
709     changed_multi |= BKE_mball_deselect_all(mb);
710     DEG_id_tag_update(&mb->id, ID_RECALC_SELECT);
711   }
712   return changed_multi;
713 }
714 
BKE_mball_select_swap(MetaBall * mb)715 bool BKE_mball_select_swap(MetaBall *mb)
716 {
717   bool changed = false;
718   LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) {
719     ml->flag ^= SELECT;
720     changed = true;
721   }
722   return changed;
723 }
724 
BKE_mball_select_swap_multi_ex(Base ** bases,int bases_len)725 bool BKE_mball_select_swap_multi_ex(Base **bases, int bases_len)
726 {
727   bool changed_multi = false;
728   for (uint ob_index = 0; ob_index < bases_len; ob_index++) {
729     Object *obedit = bases[ob_index]->object;
730     MetaBall *mb = (MetaBall *)obedit->data;
731     changed_multi |= BKE_mball_select_swap(mb);
732   }
733   return changed_multi;
734 }
735 
736 /* **** Depsgraph evaluation **** */
737 
738 /* Draw Engine */
739 
740 void (*BKE_mball_batch_cache_dirty_tag_cb)(MetaBall *mb, int mode) = NULL;
741 void (*BKE_mball_batch_cache_free_cb)(MetaBall *mb) = NULL;
742 
BKE_mball_batch_cache_dirty_tag(MetaBall * mb,int mode)743 void BKE_mball_batch_cache_dirty_tag(MetaBall *mb, int mode)
744 {
745   if (mb->batch_cache) {
746     BKE_mball_batch_cache_dirty_tag_cb(mb, mode);
747   }
748 }
BKE_mball_batch_cache_free(MetaBall * mb)749 void BKE_mball_batch_cache_free(MetaBall *mb)
750 {
751   if (mb->batch_cache) {
752     BKE_mball_batch_cache_free_cb(mb);
753   }
754 }
755