UI: Move Scene Statistics to the 3D Viewport
[blender-staging.git] / source / blender / editors / space_info / info_stats.c
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
17 /** \file
18  * \ingroup spinfo
19  */
20
21 #include <stdio.h>
22 #include <string.h>
23
24 #include "MEM_guardedalloc.h"
25
26 #include "DNA_armature_types.h"
27 #include "DNA_collection_types.h"
28 #include "DNA_curve_types.h"
29 #include "DNA_gpencil_types.h"
30 #include "DNA_lattice_types.h"
31 #include "DNA_mesh_types.h"
32 #include "DNA_meta_types.h"
33 #include "DNA_scene_types.h"
34 #include "DNA_windowmanager_types.h"
35
36 #include "BLF_api.h"
37
38 #include "BLI_listbase.h"
39 #include "BLI_math.h"
40 #include "BLI_string.h"
41 #include "BLI_utildefines.h"
42
43 #include "BLT_translation.h"
44
45 #include "BKE_blender_version.h"
46 #include "BKE_curve.h"
47 #include "BKE_displist.h"
48 #include "BKE_editmesh.h"
49 #include "BKE_gpencil.h"
50 #include "BKE_key.h"
51 #include "BKE_layer.h"
52 #include "BKE_main.h"
53 #include "BKE_object.h"
54 #include "BKE_paint.h"
55 #include "BKE_particle.h"
56 #include "BKE_scene.h"
57 #include "BKE_subdiv_ccg.h"
58
59 #include "DEG_depsgraph_query.h"
60
61 #include "ED_armature.h"
62 #include "ED_info.h"
63
64 #include "UI_resources.h"
65
66 #include "GPU_extensions.h"
67
68 #define MAX_INFO_NUM_LEN 16
69
70 typedef struct SceneStats {
71   uint64_t totvert, totvertsel;
72   uint64_t totedge, totedgesel;
73   uint64_t totface, totfacesel;
74   uint64_t totbone, totbonesel;
75   uint64_t totobj, totobjsel;
76   uint64_t totlamp, totlampsel;
77   uint64_t tottri;
78   uint64_t totgplayer, totgpframe, totgpstroke, totgppoint;
79 } SceneStats;
80
81 typedef struct SceneStatsFmt {
82   /* Totals */
83   char totvert[MAX_INFO_NUM_LEN], totvertsel[MAX_INFO_NUM_LEN];
84   char totface[MAX_INFO_NUM_LEN], totfacesel[MAX_INFO_NUM_LEN];
85   char totedge[MAX_INFO_NUM_LEN], totedgesel[MAX_INFO_NUM_LEN];
86   char totbone[MAX_INFO_NUM_LEN], totbonesel[MAX_INFO_NUM_LEN];
87   char totobj[MAX_INFO_NUM_LEN], totobjsel[MAX_INFO_NUM_LEN];
88   char totlamp[MAX_INFO_NUM_LEN], totlampsel[MAX_INFO_NUM_LEN];
89   char tottri[MAX_INFO_NUM_LEN];
90   char totgplayer[MAX_INFO_NUM_LEN], totgpframe[MAX_INFO_NUM_LEN];
91   char totgpstroke[MAX_INFO_NUM_LEN], totgppoint[MAX_INFO_NUM_LEN];
92 } SceneStatsFmt;
93
94 static bool stats_mesheval(Mesh *me_eval, bool is_selected, SceneStats *stats)
95 {
96   if (me_eval == NULL) {
97     return false;
98   }
99
100   int totvert, totedge, totface, totloop;
101   if (me_eval->runtime.subdiv_ccg != NULL) {
102     const SubdivCCG *subdiv_ccg = me_eval->runtime.subdiv_ccg;
103     BKE_subdiv_ccg_topology_counters(subdiv_ccg, &totvert, &totedge, &totface, &totloop);
104   }
105   else {
106     totvert = me_eval->totvert;
107     totedge = me_eval->totedge;
108     totface = me_eval->totpoly;
109     totloop = me_eval->totloop;
110   }
111
112   stats->totvert += totvert;
113   stats->totedge += totedge;
114   stats->totface += totface;
115   stats->tottri += poly_to_tri_count(totface, totloop);
116
117   if (is_selected) {
118     stats->totvertsel += totvert;
119     stats->totfacesel += totface;
120   }
121   return true;
122 }
123
124 static void stats_object(Object *ob, SceneStats *stats, GSet *objects_gset)
125 {
126   if ((ob->base_flag & BASE_VISIBLE_VIEWLAYER) == 0) {
127     return;
128   }
129
130   const bool is_selected = (ob->base_flag & BASE_SELECTED) != 0;
131
132   stats->totobj++;
133   if (is_selected) {
134     stats->totobjsel++;
135   }
136
137   switch (ob->type) {
138     case OB_MESH: {
139       /* we assume evaluated mesh is already built, this strictly does stats now. */
140       Mesh *me_eval = BKE_object_get_evaluated_mesh(ob);
141       if (!BLI_gset_add(objects_gset, me_eval)) {
142         break;
143       }
144       stats_mesheval(me_eval, is_selected, stats);
145       break;
146     }
147     case OB_LAMP:
148       stats->totlamp++;
149       if (is_selected) {
150         stats->totlampsel++;
151       }
152       break;
153     case OB_SURF:
154     case OB_CURVE:
155     case OB_FONT: {
156       Mesh *me_eval = BKE_object_get_evaluated_mesh(ob);
157       if ((me_eval != NULL) && !BLI_gset_add(objects_gset, me_eval)) {
158         break;
159       }
160
161       if (stats_mesheval(me_eval, is_selected, stats)) {
162         break;
163       }
164       ATTR_FALLTHROUGH; /* Fallthrough to displist. */
165     }
166     case OB_MBALL: {
167       int totv = 0, totf = 0, tottri = 0;
168
169       if (ob->runtime.curve_cache && ob->runtime.curve_cache->disp.first) {
170         /* Note: We only get the same curve_cache for instances of the same curve/font/...
171          * For simple linked duplicated objects, each has its own dispList. */
172         if (!BLI_gset_add(objects_gset, ob->runtime.curve_cache)) {
173           break;
174         }
175
176         BKE_displist_count(&ob->runtime.curve_cache->disp, &totv, &totf, &tottri);
177       }
178
179       stats->totvert += totv;
180       stats->totface += totf;
181       stats->tottri += tottri;
182
183       if (is_selected) {
184         stats->totvertsel += totv;
185         stats->totfacesel += totf;
186       }
187       break;
188     }
189     case OB_GPENCIL: {
190       if (is_selected) {
191         bGPdata *gpd = (bGPdata *)ob->data;
192         if (!BLI_gset_add(objects_gset, gpd)) {
193           break;
194         }
195         /* GPXX Review if we can move to other place when object change
196          * maybe to depsgraph evaluation
197          */
198         BKE_gpencil_stats_update(gpd);
199
200         stats->totgplayer += gpd->totlayer;
201         stats->totgpframe += gpd->totframe;
202         stats->totgpstroke += gpd->totstroke;
203         stats->totgppoint += gpd->totpoint;
204       }
205       break;
206     }
207     case OB_HAIR:
208     case OB_POINTCLOUD:
209     case OB_VOLUME: {
210       break;
211     }
212   }
213 }
214
215 static void stats_object_edit(Object *obedit, SceneStats *stats)
216 {
217   if (obedit->type == OB_MESH) {
218     BMEditMesh *em = BKE_editmesh_from_object(obedit);
219
220     stats->totvert += em->bm->totvert;
221     stats->totvertsel += em->bm->totvertsel;
222
223     stats->totedge += em->bm->totedge;
224     stats->totedgesel += em->bm->totedgesel;
225
226     stats->totface += em->bm->totface;
227     stats->totfacesel += em->bm->totfacesel;
228
229     stats->tottri += em->tottri;
230   }
231   else if (obedit->type == OB_ARMATURE) {
232     /* Armature Edit */
233     bArmature *arm = obedit->data;
234     EditBone *ebo;
235
236     for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
237       stats->totbone++;
238
239       if ((ebo->flag & BONE_CONNECTED) && ebo->parent) {
240         stats->totvert--;
241       }
242
243       if (ebo->flag & BONE_TIPSEL) {
244         stats->totvertsel++;
245       }
246       if (ebo->flag & BONE_ROOTSEL) {
247         stats->totvertsel++;
248       }
249
250       if (ebo->flag & BONE_SELECTED) {
251         stats->totbonesel++;
252       }
253
254       /* if this is a connected child and it's parent is being moved, remove our root */
255       if ((ebo->flag & BONE_CONNECTED) && (ebo->flag & BONE_ROOTSEL) && ebo->parent &&
256           (ebo->parent->flag & BONE_TIPSEL)) {
257         stats->totvertsel--;
258       }
259
260       stats->totvert += 2;
261     }
262   }
263   else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) { /* OB_FONT has no cu->editnurb */
264     /* Curve Edit */
265     Curve *cu = obedit->data;
266     Nurb *nu;
267     BezTriple *bezt;
268     BPoint *bp;
269     int a;
270     ListBase *nurbs = BKE_curve_editNurbs_get(cu);
271
272     for (nu = nurbs->first; nu; nu = nu->next) {
273       if (nu->type == CU_BEZIER) {
274         bezt = nu->bezt;
275         a = nu->pntsu;
276         while (a--) {
277           stats->totvert += 3;
278           if (bezt->f1 & SELECT) {
279             stats->totvertsel++;
280           }
281           if (bezt->f2 & SELECT) {
282             stats->totvertsel++;
283           }
284           if (bezt->f3 & SELECT) {
285             stats->totvertsel++;
286           }
287           bezt++;
288         }
289       }
290       else {
291         bp = nu->bp;
292         a = nu->pntsu * nu->pntsv;
293         while (a--) {
294           stats->totvert++;
295           if (bp->f1 & SELECT) {
296             stats->totvertsel++;
297           }
298           bp++;
299         }
300       }
301     }
302   }
303   else if (obedit->type == OB_MBALL) {
304     /* MetaBall Edit */
305     MetaBall *mball = obedit->data;
306     MetaElem *ml;
307
308     for (ml = mball->editelems->first; ml; ml = ml->next) {
309       stats->totvert++;
310       if (ml->flag & SELECT) {
311         stats->totvertsel++;
312       }
313     }
314   }
315   else if (obedit->type == OB_LATTICE) {
316     /* Lattice Edit */
317     Lattice *lt = obedit->data;
318     Lattice *editlatt = lt->editlatt->latt;
319     BPoint *bp;
320     int a;
321
322     bp = editlatt->def;
323
324     a = editlatt->pntsu * editlatt->pntsv * editlatt->pntsw;
325     while (a--) {
326       stats->totvert++;
327       if (bp->f1 & SELECT) {
328         stats->totvertsel++;
329       }
330       bp++;
331     }
332   }
333 }
334
335 static void stats_object_pose(Object *ob, SceneStats *stats)
336 {
337   if (ob->pose) {
338     bArmature *arm = ob->data;
339     bPoseChannel *pchan;
340
341     for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
342       stats->totbone++;
343       if (pchan->bone && (pchan->bone->flag & BONE_SELECTED)) {
344         if (pchan->bone->layer & arm->layer) {
345           stats->totbonesel++;
346         }
347       }
348     }
349   }
350 }
351
352 static void stats_object_sculpt_dynamic_topology(Object *ob, SceneStats *stats)
353 {
354   stats->totvert = ob->sculpt->bm->totvert;
355   stats->tottri = ob->sculpt->bm->totface;
356 }
357
358 static bool stats_is_object_dynamic_topology_sculpt(Object *ob, const eObjectMode object_mode)
359 {
360   return (ob && (object_mode & OB_MODE_SCULPT) && ob->sculpt && ob->sculpt->bm);
361 }
362
363 /* Statistics displayed in info header. Called regularly on scene changes. */
364 static void stats_update(Depsgraph *depsgraph, ViewLayer *view_layer)
365 {
366   SceneStats stats = {0};
367   Object *ob = OBACT(view_layer);
368   Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
369
370   if (obedit) {
371     /* Edit Mode */
372     FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, ((View3D *)NULL), ob->type, ob->mode, ob_iter) {
373       stats_object_edit(ob_iter, &stats);
374     }
375     FOREACH_OBJECT_IN_MODE_END;
376   }
377   else if (ob && (ob->mode & OB_MODE_POSE)) {
378     /* Pose Mode */
379     stats_object_pose(ob, &stats);
380   }
381   else if (ob && stats_is_object_dynamic_topology_sculpt(ob, ob->mode)) {
382     /* Dynamic-topology sculpt mode */
383     stats_object_sculpt_dynamic_topology(ob, &stats);
384   }
385   else {
386     /* Objects */
387     GSet *objects_gset = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
388     DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (depsgraph, ob_iter) {
389       stats_object(ob_iter, &stats, objects_gset);
390     }
391     DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END;
392     BLI_gset_free(objects_gset, NULL);
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 const char *footer_string(ViewLayer *view_layer)
403 {
404 #define MAX_INFO_MEM_LEN 64
405   char memstr[MAX_INFO_MEM_LEN];
406   char gpumemstr[MAX_INFO_MEM_LEN] = "";
407   char formatted_mem[15];
408   size_t ofs = 0;
409
410   uintptr_t mem_in_use = MEM_get_memory_in_use();
411   uintptr_t mmap_in_use = MEM_get_mapped_memory_in_use();
412
413   /* get memory statistics */
414   BLI_str_format_byte_unit(formatted_mem, mem_in_use - mmap_in_use, false);
415   ofs = BLI_snprintf(memstr, MAX_INFO_MEM_LEN, TIP_("Mem: %s"), formatted_mem);
416
417   if (mmap_in_use) {
418     BLI_str_format_byte_unit(formatted_mem, mmap_in_use, false);
419     BLI_snprintf(memstr + ofs, MAX_INFO_MEM_LEN - ofs, TIP_(" (%s)"), formatted_mem);
420   }
421
422   if (GPU_mem_stats_supported()) {
423     int gpu_free_mem, gpu_tot_memory;
424
425     GPU_mem_stats_get(&gpu_tot_memory, &gpu_free_mem);
426
427     BLI_str_format_byte_unit(formatted_mem, gpu_free_mem, false);
428     ofs = BLI_snprintf(gpumemstr, MAX_INFO_MEM_LEN, TIP_(" | Free GPU Mem: %s"), formatted_mem);
429
430     if (gpu_tot_memory) {
431       BLI_str_format_byte_unit(formatted_mem, gpu_tot_memory, false);
432       BLI_snprintf(gpumemstr + ofs, MAX_INFO_MEM_LEN - ofs, TIP_("/%s"), formatted_mem);
433     }
434   }
435
436   BLI_snprintf(view_layer->footer_str,
437                sizeof(view_layer->footer_str),
438                "%s%s | %s",
439                memstr,
440                gpumemstr,
441                versionstr);
442
443   return view_layer->footer_str;
444
445 #undef MAX_INFO_MEM_LEN
446 }
447
448 void ED_info_stats_clear(ViewLayer *view_layer)
449 {
450   if (view_layer->stats) {
451     MEM_freeN(view_layer->stats);
452     view_layer->stats = NULL;
453   }
454 }
455
456 const char *ED_info_footer_string(ViewLayer *view_layer)
457 {
458   return footer_string(view_layer);
459 }
460
461 static void stats_row(int col1,
462                       const char *key,
463                       int col2,
464                       const char *value1,
465                       const char *value2,
466                       int *y,
467                       int height)
468 {
469   *y -= height;
470   BLF_draw_default(col1, *y, 0.0f, key, 128);
471   char values[128];
472   BLI_snprintf(values, sizeof(values), (value2) ? "%s/%s" : "%s", value1, value2);
473   BLF_draw_default(col2, *y, 0.0f, values, sizeof(values));
474 }
475
476 void ED_info_draw_stats(
477     Main *bmain, Scene *scene, ViewLayer *view_layer, int x, int *y, int height)
478 {
479   /* Looping through dependency graph when interface is locked is not safe.
480    * The interface is marked as locked when jobs wants to modify the
481    * dependency graph. */
482   wmWindowManager *wm = bmain->wm.first;
483   if (wm->is_interface_locked) {
484     return;
485   }
486
487   Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
488   if (!view_layer->stats) {
489     stats_update(depsgraph, view_layer);
490   }
491
492   SceneStats *stats = view_layer->stats;
493   SceneStatsFmt stats_fmt;
494
495   /* Generate formatted numbers. */
496 #define SCENE_STATS_FMT_INT(_id) BLI_str_format_uint64_grouped(stats_fmt._id, stats->_id)
497
498   SCENE_STATS_FMT_INT(totvert);
499   SCENE_STATS_FMT_INT(totvertsel);
500
501   SCENE_STATS_FMT_INT(totedge);
502   SCENE_STATS_FMT_INT(totedgesel);
503
504   SCENE_STATS_FMT_INT(totface);
505   SCENE_STATS_FMT_INT(totfacesel);
506
507   SCENE_STATS_FMT_INT(totbone);
508   SCENE_STATS_FMT_INT(totbonesel);
509
510   SCENE_STATS_FMT_INT(totobj);
511   SCENE_STATS_FMT_INT(totobjsel);
512
513   SCENE_STATS_FMT_INT(totlamp);
514   SCENE_STATS_FMT_INT(totlampsel);
515
516   SCENE_STATS_FMT_INT(tottri);
517
518   SCENE_STATS_FMT_INT(totgplayer);
519   SCENE_STATS_FMT_INT(totgpframe);
520   SCENE_STATS_FMT_INT(totgpstroke);
521   SCENE_STATS_FMT_INT(totgppoint);
522
523 #undef SCENE_STATS_FMT_INT
524
525   Object *ob = OBACT(view_layer);
526   Object *obedit = OBEDIT_FROM_OBACT(ob);
527   eObjectMode object_mode = ob ? ob->mode : OB_MODE_OBJECT;
528   const int font_id = BLF_default();
529
530   UI_FontThemeColor(font_id, TH_TEXT_HI);
531   BLF_enable(font_id, BLF_SHADOW);
532   BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
533   BLF_shadow_offset(font_id, 1, -1);
534
535   /* Translated labels for each stat row. */
536   enum {
537     OBJ,
538     VERTS,
539     EDGES,
540     FACES,
541     TRIS,
542     BONES,
543     LAYERS,
544     FRAMES,
545     STROKES,
546     POINTS,
547     MAX_LABELS_COUNT
548   };
549   char labels[MAX_LABELS_COUNT][64];
550
551   STRNCPY(labels[OBJ], IFACE_("Objects"));
552   STRNCPY(labels[VERTS], IFACE_("Vertices"));
553   STRNCPY(labels[EDGES], IFACE_("Edges"));
554   STRNCPY(labels[FACES], IFACE_("Faces"));
555   STRNCPY(labels[TRIS], IFACE_("Triangles"));
556   STRNCPY(labels[BONES], IFACE_("Bones"));
557   STRNCPY(labels[LAYERS], IFACE_("Layers"));
558   STRNCPY(labels[FRAMES], IFACE_("Frames"));
559   STRNCPY(labels[STROKES], IFACE_("Strokes"));
560   STRNCPY(labels[POINTS], IFACE_("Points"));
561
562   int longest_label = 0;
563   int i;
564   for (i = 0; i < MAX_LABELS_COUNT; ++i) {
565     longest_label = max_ii(longest_label, BLF_width(font_id, labels[i], sizeof(labels[i])));
566   }
567
568   int col1 = x;
569   int col2 = x + longest_label + (0.5f * U.widget_unit);
570
571   /* Add some extra margin above this section. */
572   *y -= (0.5f * height);
573
574   if (object_mode == OB_MODE_OBJECT) {
575     stats_row(col1, labels[OBJ], col2, stats_fmt.totobjsel, stats_fmt.totobj, y, height);
576   }
577
578   if (obedit) {
579     if (obedit->type == OB_MESH) {
580       stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height);
581       stats_row(col1, labels[EDGES], col2, stats_fmt.totedgesel, stats_fmt.totedge, y, height);
582       stats_row(col1, labels[FACES], col2, stats_fmt.totfacesel, stats_fmt.totface, y, height);
583       stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height);
584     }
585     else if (obedit->type == OB_ARMATURE) {
586       stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height);
587       stats_row(col1, labels[BONES], col2, stats_fmt.totbonesel, stats_fmt.totbone, y, height);
588     }
589     else {
590       stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height);
591     }
592   }
593   else if (ob && (object_mode & OB_MODE_POSE)) {
594     stats_row(col1, labels[BONES], col2, stats_fmt.totbonesel, stats_fmt.totbone, y, height);
595   }
596   else if ((ob) && (ob->type == OB_GPENCIL)) {
597     stats_row(col1, labels[LAYERS], col2, stats_fmt.totgplayer, NULL, y, height);
598     stats_row(col1, labels[FRAMES], col2, stats_fmt.totgpframe, NULL, y, height);
599     stats_row(col1, labels[STROKES], col2, stats_fmt.totgpstroke, NULL, y, height);
600     stats_row(col1, labels[POINTS], col2, stats_fmt.totgppoint, NULL, y, height);
601   }
602   else if (stats_is_object_dynamic_topology_sculpt(ob, object_mode)) {
603     stats_row(col1, labels[VERTS], col2, stats_fmt.totvert, NULL, y, height);
604     stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height);
605   }
606   else {
607     stats_row(col1, labels[VERTS], col2, stats_fmt.totvert, NULL, y, height);
608     stats_row(col1, labels[EDGES], col2, stats_fmt.totedge, NULL, y, height);
609     stats_row(col1, labels[FACES], col2, stats_fmt.totface, NULL, y, height);
610     stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height);
611   }
612
613   BLF_disable(font_id, BLF_SHADOW);
614 }