Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / space_info / info_stats.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Blender Foundation
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/editors/space_info/info_stats.c
24  *  \ingroup spinfo
25  */
26
27
28 #include <stdio.h>
29 #include <string.h>
30
31 #include "MEM_guardedalloc.h"
32
33 #include "DNA_armature_types.h"
34 #include "DNA_curve_types.h"
35 #include "DNA_group_types.h"
36 #include "DNA_lattice_types.h"
37 #include "DNA_meta_types.h"
38 #include "DNA_scene_types.h"
39
40 #include "BLI_listbase.h"
41 #include "BLI_math.h"
42 #include "BLI_string.h"
43 #include "BLI_utildefines.h"
44
45 #include "BLT_translation.h"
46
47 #include "BKE_anim.h"
48 #include "BKE_blender_version.h"
49 #include "BKE_curve.h"
50 #include "BKE_displist.h"
51 #include "BKE_DerivedMesh.h"
52 #include "BKE_key.h"
53 #include "BKE_layer.h"
54 #include "BKE_paint.h"
55 #include "BKE_particle.h"
56 #include "BKE_editmesh.h"
57 #include "BKE_object.h"
58
59 #include "ED_info.h"
60 #include "ED_armature.h"
61
62 #include "GPU_extensions.h"
63
64 #define MAX_INFO_LEN 512
65 #define MAX_INFO_NUM_LEN 16
66
67 typedef struct SceneStats {
68         int totvert, totvertsel;
69         int totedge, totedgesel;
70         int totface, totfacesel;
71         int totbone, totbonesel;
72         int totobj,  totobjsel;
73         int totlamp, totlampsel;
74         int tottri;
75
76         char infostr[MAX_INFO_LEN];
77 } SceneStats;
78
79 typedef struct SceneStatsFmt {
80         /* Totals */
81         char totvert[MAX_INFO_NUM_LEN], totvertsel[MAX_INFO_NUM_LEN];
82         char totface[MAX_INFO_NUM_LEN], totfacesel[MAX_INFO_NUM_LEN];
83         char totedge[MAX_INFO_NUM_LEN], totedgesel[MAX_INFO_NUM_LEN];
84         char totbone[MAX_INFO_NUM_LEN], totbonesel[MAX_INFO_NUM_LEN];
85         char totobj[MAX_INFO_NUM_LEN], totobjsel[MAX_INFO_NUM_LEN];
86         char totlamp[MAX_INFO_NUM_LEN], totlampsel[MAX_INFO_NUM_LEN];
87         char tottri[MAX_INFO_NUM_LEN];
88 } SceneStatsFmt;
89
90 static void stats_object(Object *ob, int sel, int totob, SceneStats *stats)
91 {
92         switch (ob->type) {
93                 case OB_MESH:
94                 {
95                         /* we assume derivedmesh is already built, this strictly does stats now. */
96                         DerivedMesh *dm = ob->derivedFinal;
97                         int totvert, totedge, totface, totloop;
98
99                         if (dm) {
100                                 totvert = dm->getNumVerts(dm);
101                                 totedge = dm->getNumEdges(dm);
102                                 totface = dm->getNumPolys(dm);
103                                 totloop = dm->getNumLoops(dm);
104
105                                 stats->totvert += totvert * totob;
106                                 stats->totedge += totedge * totob;
107                                 stats->totface += totface * totob;
108                                 stats->tottri  += poly_to_tri_count(totface, totloop) * totob;
109
110                                 if (sel) {
111                                         stats->totvertsel += totvert;
112                                         stats->totfacesel += totface;
113                                 }
114                         }
115                         break;
116                 }
117                 case OB_LAMP:
118                         stats->totlamp += totob;
119                         if (sel) {
120                                 stats->totlampsel += totob;
121                         }
122                         break;
123                 case OB_SURF:
124                 case OB_CURVE:
125                 case OB_FONT:
126                 case OB_MBALL:
127                 {
128                         int totv = 0, totf = 0, tottri = 0;
129
130                         if (ob->curve_cache && ob->curve_cache->disp.first)
131                                 BKE_displist_count(&ob->curve_cache->disp, &totv, &totf, &tottri);
132
133                         totv   *= totob;
134                         totf   *= totob;
135                         tottri *= totob;
136
137                         stats->totvert += totv;
138                         stats->totface += totf;
139                         stats->tottri  += tottri;
140
141                         if (sel) {
142                                 stats->totvertsel += totv;
143                                 stats->totfacesel += totf;
144                         }
145                         break;
146                 }
147         }
148 }
149
150 static void stats_object_edit(Object *obedit, SceneStats *stats)
151 {
152         if (obedit->type == OB_MESH) {
153                 BMEditMesh *em = BKE_editmesh_from_object(obedit);
154
155                 stats->totvert = em->bm->totvert;
156                 stats->totvertsel = em->bm->totvertsel;
157
158                 stats->totedge = em->bm->totedge;
159                 stats->totedgesel = em->bm->totedgesel;
160
161                 stats->totface = em->bm->totface;
162                 stats->totfacesel = em->bm->totfacesel;
163
164                 stats->tottri = em->tottri;
165         }
166         else if (obedit->type == OB_ARMATURE) {
167                 /* Armature Edit */
168                 bArmature *arm = obedit->data;
169                 EditBone *ebo;
170
171                 for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
172                         stats->totbone++;
173
174                         if ((ebo->flag & BONE_CONNECTED) && ebo->parent)
175                                 stats->totvert--;
176
177                         if (ebo->flag & BONE_TIPSEL)
178                                 stats->totvertsel++;
179                         if (ebo->flag & BONE_ROOTSEL)
180                                 stats->totvertsel++;
181
182                         if (ebo->flag & BONE_SELECTED) stats->totbonesel++;
183
184                         /* if this is a connected child and it's parent is being moved, remove our root */
185                         if ((ebo->flag & BONE_CONNECTED) && (ebo->flag & BONE_ROOTSEL) &&
186                             ebo->parent && (ebo->parent->flag & BONE_TIPSEL))
187                         {
188                                 stats->totvertsel--;
189                         }
190
191                         stats->totvert += 2;
192                 }
193         }
194         else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) { /* OB_FONT has no cu->editnurb */
195                 /* Curve Edit */
196                 Curve *cu = obedit->data;
197                 Nurb *nu;
198                 BezTriple *bezt;
199                 BPoint *bp;
200                 int a;
201                 ListBase *nurbs = BKE_curve_editNurbs_get(cu);
202
203                 for (nu = nurbs->first; nu; nu = nu->next) {
204                         if (nu->type == CU_BEZIER) {
205                                 bezt = nu->bezt;
206                                 a = nu->pntsu;
207                                 while (a--) {
208                                         stats->totvert += 3;
209                                         if (bezt->f1 & SELECT) stats->totvertsel++;
210                                         if (bezt->f2 & SELECT) stats->totvertsel++;
211                                         if (bezt->f3 & SELECT) stats->totvertsel++;
212                                         bezt++;
213                                 }
214                         }
215                         else {
216                                 bp = nu->bp;
217                                 a = nu->pntsu * nu->pntsv;
218                                 while (a--) {
219                                         stats->totvert++;
220                                         if (bp->f1 & SELECT) stats->totvertsel++;
221                                         bp++;
222                                 }
223                         }
224                 }
225         }
226         else if (obedit->type == OB_MBALL) {
227                 /* MetaBall Edit */
228                 MetaBall *mball = obedit->data;
229                 MetaElem *ml;
230
231                 for (ml = mball->editelems->first; ml; ml = ml->next) {
232                         stats->totvert++;
233                         if (ml->flag & SELECT) stats->totvertsel++;
234                 }
235         }
236         else if (obedit->type == OB_LATTICE) {
237                 /* Lattice Edit */
238                 Lattice *lt = obedit->data;
239                 Lattice *editlatt = lt->editlatt->latt;
240                 BPoint *bp;
241                 int a;
242
243                 bp = editlatt->def;
244
245                 a = editlatt->pntsu * editlatt->pntsv * editlatt->pntsw;
246                 while (a--) {
247                         stats->totvert++;
248                         if (bp->f1 & SELECT) stats->totvertsel++;
249                         bp++;
250                 }
251         }
252 }
253
254 static void stats_object_pose(Object *ob, SceneStats *stats)
255 {
256         if (ob->pose) {
257                 bArmature *arm = ob->data;
258                 bPoseChannel *pchan;
259
260                 for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
261                         stats->totbone++;
262                         if (pchan->bone && (pchan->bone->flag & BONE_SELECTED))
263                                 if (pchan->bone->layer & arm->layer)
264                                         stats->totbonesel++;
265                 }
266         }
267 }
268
269 static void stats_object_sculpt_dynamic_topology(Object *ob, SceneStats *stats)
270 {
271         stats->totvert = ob->sculpt->bm->totvert;
272         stats->tottri = ob->sculpt->bm->totface;
273 }
274
275 static void stats_dupli_object_group_count(Collection *collection, int *count)
276 {
277         *count += BLI_listbase_count(&collection->gobject);
278
279         for (CollectionChild *child = collection->children.first; child; child = child->next) {
280                 stats_dupli_object_group_count(child->collection, count);
281         }
282 }
283
284 static void stats_dupli_object_group_doit(Collection *collection, SceneStats *stats, ParticleSystem *psys,
285                                           const int totgroup, int *cur)
286 {
287         for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
288                 int tot = count_particles_mod(psys, totgroup, *cur);
289                 stats_object(cob->ob, 0, tot, stats);
290                 (*cur)++;
291         }
292
293         for (CollectionChild *child = collection->children.first; child; child = child->next) {
294                 stats_dupli_object_group_doit(child->collection, stats, psys, totgroup, cur);
295         }
296 }
297
298 static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats)
299 {
300         if (base->flag & BASE_SELECTED) stats->totobjsel++;
301
302         if (ob->transflag & OB_DUPLIPARTS) {
303                 /* Dupli Particles */
304                 ParticleSystem *psys;
305                 ParticleSettings *part;
306
307                 for (psys = ob->particlesystem.first; psys; psys = psys->next) {
308                         part = psys->part;
309
310                         if (part->draw_as == PART_DRAW_OB && part->dup_ob) {
311                                 int tot = count_particles(psys);
312                                 stats_object(part->dup_ob, 0, tot, stats);
313                         }
314                         else if (part->draw_as == PART_DRAW_GR && part->dup_group) {
315                                 int totgroup = 0, cur = 0;
316
317                                 Collection *collection = part->dup_group;
318                                 stats_dupli_object_group_count(collection, &totgroup);
319                                 stats_dupli_object_group_doit(collection, stats, psys, totgroup, &cur);
320                         }
321                 }
322
323                 stats_object(ob, base->flag & BASE_SELECTED, 1, stats);
324                 stats->totobj++;
325         }
326         else if (ob->parent && (ob->parent->transflag & (OB_DUPLIVERTS | OB_DUPLIFACES))) {
327                 /* Dupli Verts/Faces */
328                 int tot;
329
330                 /* metaball dupli-instances are tessellated once */
331                 if (ob->type == OB_MBALL) {
332                         tot = 1;
333                 }
334                 else {
335                         tot = count_duplilist(ob->parent);
336                 }
337
338                 stats->totobj += tot;
339                 stats_object(ob, base->flag & BASE_SELECTED, tot, stats);
340         }
341         else if (ob->transflag & OB_DUPLIFRAMES) {
342                 /* Dupli Frames */
343                 int tot = count_duplilist(ob);
344                 stats->totobj += tot;
345                 stats_object(ob, base->flag & BASE_SELECTED, tot, stats);
346         }
347         else if ((ob->transflag & OB_DUPLICOLLECTION) && ob->dup_group) {
348                 /* Dupli Group */
349                 int tot = count_duplilist(ob);
350                 stats->totobj += tot;
351                 stats_object(ob, base->flag & BASE_SELECTED, tot, stats);
352         }
353         else {
354                 /* No Dupli */
355                 stats_object(ob, base->flag & BASE_SELECTED, 1, stats);
356                 stats->totobj++;
357         }
358 }
359
360 static bool stats_is_object_dynamic_topology_sculpt(Object *ob, const eObjectMode object_mode)
361 {
362         return (ob &&
363                 (object_mode & OB_MODE_SCULPT) &&
364                 ob->sculpt && ob->sculpt->bm);
365 }
366
367 /* Statistics displayed in info header. Called regularly on scene changes. */
368 static void stats_update(ViewLayer *view_layer)
369 {
370         SceneStats stats = {0};
371         Object *ob = OBACT(view_layer);
372         Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
373         Base *base;
374
375         if (obedit) {
376                 /* Edit Mode */
377                 stats_object_edit(ob, &stats);
378         }
379         else if (ob && (ob->mode & OB_MODE_POSE)) {
380                 /* Pose Mode */
381                 stats_object_pose(ob, &stats);
382         }
383         else if (ob && stats_is_object_dynamic_topology_sculpt(ob, ob->mode)) {
384                 /* Dynamic-topology sculpt mode */
385                 stats_object_sculpt_dynamic_topology(ob, &stats);
386         }
387         else {
388                 /* Objects */
389                 for (base = view_layer->object_bases.first; base; base = base->next)
390                         if (base->flag & BASE_VISIBLED) {
391                                 stats_dupli_object(base, base->object, &stats);
392                         }
393         }
394
395         if (!view_layer->stats) {
396                 view_layer->stats = MEM_callocN(sizeof(SceneStats), "SceneStats");
397         }
398
399         *(view_layer->stats) = stats;
400 }
401
402 static void stats_string(ViewLayer *view_layer)
403 {
404 #define MAX_INFO_MEM_LEN  64
405         SceneStats *stats = view_layer->stats;
406         SceneStatsFmt stats_fmt;
407         Object *ob = OBACT(view_layer);
408         Object *obedit = OBEDIT_FROM_OBACT(ob);
409         eObjectMode object_mode = ob ? ob->mode : OB_MODE_OBJECT;
410         uintptr_t mem_in_use, mmap_in_use;
411         char memstr[MAX_INFO_MEM_LEN];
412         char gpumemstr[MAX_INFO_MEM_LEN] = "";
413         char formatted_mem[15];
414         char *s;
415         size_t ofs = 0;
416
417         mem_in_use = MEM_get_memory_in_use();
418         mmap_in_use = MEM_get_mapped_memory_in_use();
419
420
421         /* Generate formatted numbers */
422 #define SCENE_STATS_FMT_INT(_id) \
423         BLI_str_format_int_grouped(stats_fmt._id, stats->_id)
424
425         SCENE_STATS_FMT_INT(totvert);
426         SCENE_STATS_FMT_INT(totvertsel);
427
428         SCENE_STATS_FMT_INT(totedge);
429         SCENE_STATS_FMT_INT(totedgesel);
430
431         SCENE_STATS_FMT_INT(totface);
432         SCENE_STATS_FMT_INT(totfacesel);
433
434         SCENE_STATS_FMT_INT(totbone);
435         SCENE_STATS_FMT_INT(totbonesel);
436
437         SCENE_STATS_FMT_INT(totobj);
438         SCENE_STATS_FMT_INT(totobjsel);
439
440         SCENE_STATS_FMT_INT(totlamp);
441         SCENE_STATS_FMT_INT(totlampsel);
442
443         SCENE_STATS_FMT_INT(tottri);
444
445 #undef SCENE_STATS_FMT_INT
446
447
448         /* get memory statistics */
449         BLI_str_format_byte_unit(formatted_mem, mem_in_use - mmap_in_use, true);
450         ofs = BLI_snprintf(memstr, MAX_INFO_MEM_LEN, IFACE_(" | Mem: %s"), formatted_mem);
451
452         if (mmap_in_use) {
453                 BLI_str_format_byte_unit(formatted_mem, mmap_in_use, true);
454                 BLI_snprintf(memstr + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_(" (%s)"), formatted_mem);
455         }
456
457         if (GPU_mem_stats_supported()) {
458                 int gpu_free_mem, gpu_tot_memory;
459
460                 GPU_mem_stats_get(&gpu_tot_memory, &gpu_free_mem);
461
462                 BLI_str_format_byte_unit(formatted_mem, gpu_free_mem, true);
463                 ofs = BLI_snprintf(gpumemstr, MAX_INFO_MEM_LEN, IFACE_(" | Free GPU Mem: %s"), formatted_mem);
464
465                 if (gpu_tot_memory) {
466                         BLI_str_format_byte_unit(formatted_mem, gpu_tot_memory, true);
467                         BLI_snprintf(gpumemstr + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_("/%s"), formatted_mem);
468                 }
469         }
470
471         s = stats->infostr;
472         ofs = 0;
473
474         ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, "%s | ", versionstr);
475
476         if (obedit) {
477                 if (BKE_keyblock_from_object(obedit))
478                         ofs += BLI_strncpy_rlen(s + ofs, IFACE_("(Key) "), MAX_INFO_LEN - ofs);
479
480                 if (obedit->type == OB_MESH) {
481                         ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs,
482                                             IFACE_("Verts:%s/%s | Edges:%s/%s | Faces:%s/%s | Tris:%s"),
483                                             stats_fmt.totvertsel, stats_fmt.totvert, stats_fmt.totedgesel, stats_fmt.totedge,
484                                             stats_fmt.totfacesel, stats_fmt.totface, stats_fmt.tottri);
485                 }
486                 else if (obedit->type == OB_ARMATURE) {
487                         ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%s/%s | Bones:%s/%s"), stats_fmt.totvertsel,
488                                             stats_fmt.totvert, stats_fmt.totbonesel, stats_fmt.totbone);
489                 }
490                 else {
491                         ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%s/%s"), stats_fmt.totvertsel,
492                                             stats_fmt.totvert);
493                 }
494
495                 ofs += BLI_strncpy_rlen(s + ofs, memstr, MAX_INFO_LEN - ofs);
496                 ofs += BLI_strncpy_rlen(s + ofs, gpumemstr, MAX_INFO_LEN - ofs);
497         }
498         else if (ob && (object_mode & OB_MODE_POSE)) {
499                 ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Bones:%s/%s %s%s"),
500                                     stats_fmt.totbonesel, stats_fmt.totbone, memstr, gpumemstr);
501         }
502         else if (stats_is_object_dynamic_topology_sculpt(ob, object_mode)) {
503                 ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%s | Tris:%s%s"), stats_fmt.totvert,
504                                     stats_fmt.tottri, gpumemstr);
505         }
506         else {
507                 ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs,
508                                     IFACE_("Verts:%s | Faces:%s | Tris:%s | Objects:%s/%s | Lamps:%s/%s%s%s"),
509                                     stats_fmt.totvert, stats_fmt.totface,
510                                     stats_fmt.tottri, stats_fmt.totobjsel,
511                                     stats_fmt.totobj, stats_fmt.totlampsel,
512                                     stats_fmt.totlamp, memstr, gpumemstr);
513         }
514
515         if (ob)
516                 BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, " | %s", ob->id.name + 2);
517 #undef MAX_INFO_MEM_LEN
518 }
519
520 #undef MAX_INFO_LEN
521
522 void ED_info_stats_clear(ViewLayer *view_layer)
523 {
524         if (view_layer->stats) {
525                 MEM_freeN(view_layer->stats);
526                 view_layer->stats = NULL;
527         }
528 }
529
530 const char *ED_info_stats_string(Scene *UNUSED(scene), ViewLayer *view_layer)
531 {
532         if (!view_layer->stats) {
533                 stats_update(view_layer);
534         }
535         stats_string(view_layer);
536         return view_layer->stats->infostr;
537 }