Blender V4.3
info_stats.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cstdio>
10#include <cstring>
11
12#include "MEM_guardedalloc.h"
13
14#include "DNA_armature_types.h"
15#include "DNA_curve_types.h"
18#include "DNA_lattice_types.h"
19#include "DNA_mesh_types.h"
20#include "DNA_meta_types.h"
21#include "DNA_scene_types.h"
22#include "DNA_space_types.h"
24
25#include "BLF_api.hh"
26
27#include "BLI_listbase.h"
28#include "BLI_math_geom.h"
29#include "BLI_span.hh"
30#include "BLI_string.h"
31#include "BLI_string_utf8.h"
32#include "BLI_timecode.h"
33#include "BLI_utildefines.h"
34
35#include "BLT_translation.hh"
36
37#include "BKE_action.hh"
38#include "BKE_armature.hh"
39#include "BKE_blender_version.h"
40#include "BKE_curve.hh"
41#include "BKE_curves.hh"
42#include "BKE_editmesh.hh"
43#include "BKE_gpencil_legacy.h"
44#include "BKE_grease_pencil.hh"
45#include "BKE_key.hh"
46#include "BKE_layer.hh"
47#include "BKE_main.hh"
48#include "BKE_mesh.hh"
49#include "BKE_object.hh"
50#include "BKE_paint.hh"
51#include "BKE_pbvh_api.hh"
52#include "BKE_scene.hh"
53#include "BKE_subdiv_ccg.hh"
55
57
58#include "ED_info.hh"
59
60#include "WM_api.hh"
61
62#include "UI_resources.hh"
63
64#include "GPU_capabilities.hh"
65
67
68struct SceneStats {
69 uint64_t totvert, totvertsel, totvertsculpt;
70 uint64_t totedge, totedgesel;
71 uint64_t totface, totfacesel, totfacesculpt;
72 uint64_t totbone, totbonesel;
73 uint64_t totobj, totobjsel;
74 uint64_t totlamp, totlampsel;
75 uint64_t tottri, tottrisel;
76 uint64_t totgplayer, totgpframe, totgpstroke, totgppoint;
77};
78
95
96static bool stats_mesheval(const Mesh *mesh_eval, bool is_selected, SceneStats *stats)
97{
98 if (mesh_eval == nullptr) {
99 return false;
100 }
101
102 int totvert, totedge, totface, totloop;
103
104 const SubsurfRuntimeData *subsurf_runtime_data = mesh_eval->runtime->subsurf_runtime_data;
105
106 if (const std::unique_ptr<SubdivCCG> &subdiv_ccg = mesh_eval->runtime->subdiv_ccg) {
107 BKE_subdiv_ccg_topology_counters(*subdiv_ccg, totvert, totedge, totface, totloop);
108 }
109 else if (subsurf_runtime_data && subsurf_runtime_data->resolution != 0) {
110 totvert = subsurf_runtime_data->stats_totvert;
111 totedge = subsurf_runtime_data->stats_totedge;
112 totface = subsurf_runtime_data->stats_faces_num;
113 totloop = subsurf_runtime_data->stats_totloop;
114 }
115 else {
116 totvert = mesh_eval->verts_num;
117 totedge = mesh_eval->edges_num;
118 totface = mesh_eval->faces_num;
119 totloop = mesh_eval->corners_num;
120 }
121
122 stats->totvert += totvert;
123 stats->totedge += totedge;
124 stats->totface += totface;
125
126 const int tottri = poly_to_tri_count(totface, totloop);
127 stats->tottri += tottri;
128
129 if (is_selected) {
130 stats->totvertsel += totvert;
131 stats->totedgesel += totedge;
132 stats->totfacesel += totface;
133 stats->tottrisel += tottri;
134 }
135 return true;
136}
137
138static void stats_object(Object *ob,
139 const View3D *v3d_local,
140 SceneStats *stats,
141 GSet *objects_gset)
142{
144 return;
145 }
146
147 if (v3d_local && !BKE_object_is_visible_in_viewport(v3d_local, ob)) {
148 return;
149 }
150
151 const bool is_selected = (ob->base_flag & BASE_SELECTED) != 0;
152
153 stats->totobj++;
154 if (is_selected) {
155 stats->totobjsel++;
156 }
157
158 switch (ob->type) {
159 case OB_MESH: {
160 /* we assume evaluated mesh is already built, this strictly does stats now. */
161 const Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
162 if (!BLI_gset_add(objects_gset, (void *)mesh_eval)) {
163 break;
164 }
165 stats_mesheval(mesh_eval, is_selected, stats);
166 break;
167 }
168 case OB_LAMP:
169 stats->totlamp++;
170 if (is_selected) {
171 stats->totlampsel++;
172 }
173 break;
174 case OB_GREASE_PENCIL: {
175 if (!is_selected) {
176 break;
177 }
178
179 const GreasePencil *grease_pencil = static_cast<GreasePencil *>(ob->data);
180
181 for (const GreasePencilDrawingBase *drawing_base : grease_pencil->drawings()) {
182 const GreasePencilDrawing *drawing = reinterpret_cast<const GreasePencilDrawing *>(
183 drawing_base);
184 const blender::bke::CurvesGeometry &curves = drawing->wrap().strokes();
185
186 stats->totgppoint += curves.points_num();
187 stats->totgpstroke += curves.curves_num();
188 }
189
190 for (const blender::bke::greasepencil::Layer *layer : grease_pencil->layers()) {
191 stats->totgpframe += layer->frames().size();
192 }
193
194 stats->totgplayer += grease_pencil->layers().size();
195 break;
196 }
197 case OB_CURVES:
198 case OB_POINTCLOUD:
199 case OB_VOLUME: {
200 break;
201 }
202 }
203}
204
205static void stats_object_edit(Object *obedit, SceneStats *stats)
206{
207 if (obedit->type == OB_MESH) {
209
210 stats->totvert += em->bm->totvert;
211 stats->totvertsel += em->bm->totvertsel;
212
213 stats->totedge += em->bm->totedge;
214 stats->totedgesel += em->bm->totedgesel;
215
216 stats->totface += em->bm->totface;
217 stats->totfacesel += em->bm->totfacesel;
218
219 stats->tottri += em->looptris.size();
220 }
221 else if (obedit->type == OB_ARMATURE) {
222 /* Armature Edit */
223 bArmature *arm = static_cast<bArmature *>(obedit->data);
224
225 LISTBASE_FOREACH (EditBone *, ebo, arm->edbo) {
226 stats->totbone++;
227
228 if ((ebo->flag & BONE_CONNECTED) && ebo->parent) {
229 stats->totvert--;
230 }
231
232 if (ebo->flag & BONE_TIPSEL) {
233 stats->totvertsel++;
234 }
235 if (ebo->flag & BONE_ROOTSEL) {
236 stats->totvertsel++;
237 }
238
239 if (ebo->flag & BONE_SELECTED) {
240 stats->totbonesel++;
241 }
242
243 /* if this is a connected child and its parent is being moved, remove our root */
244 if ((ebo->flag & BONE_CONNECTED) && (ebo->flag & BONE_ROOTSEL) && ebo->parent &&
245 (ebo->parent->flag & BONE_TIPSEL))
246 {
247 stats->totvertsel--;
248 }
249
250 stats->totvert += 2;
251 }
252 }
253 else if (ELEM(obedit->type, OB_CURVES_LEGACY, OB_SURF)) { /* OB_FONT has no cu->editnurb */
254 /* Curve Edit */
255 Curve *cu = static_cast<Curve *>(obedit->data);
256 BezTriple *bezt;
257 BPoint *bp;
258 int a;
260
261 LISTBASE_FOREACH (Nurb *, nu, nurbs) {
262 if (nu->type == CU_BEZIER) {
263 bezt = nu->bezt;
264 a = nu->pntsu;
265 while (a--) {
266 stats->totvert += 3;
267 if (bezt->f1 & SELECT) {
268 stats->totvertsel++;
269 }
270 if (bezt->f2 & SELECT) {
271 stats->totvertsel++;
272 }
273 if (bezt->f3 & SELECT) {
274 stats->totvertsel++;
275 }
276 bezt++;
277 }
278 }
279 else {
280 bp = nu->bp;
281 a = nu->pntsu * nu->pntsv;
282 while (a--) {
283 stats->totvert++;
284 if (bp->f1 & SELECT) {
285 stats->totvertsel++;
286 }
287 bp++;
288 }
289 }
290 }
291 }
292 else if (obedit->type == OB_MBALL) {
293 /* MetaBall Edit */
294 MetaBall *mball = static_cast<MetaBall *>(obedit->data);
295
296 LISTBASE_FOREACH (MetaElem *, ml, mball->editelems) {
297 stats->totvert++;
298 if (ml->flag & SELECT) {
299 stats->totvertsel++;
300 }
301 }
302 }
303 else if (obedit->type == OB_LATTICE) {
304 /* Lattice Edit */
305 Lattice *lt = static_cast<Lattice *>(obedit->data);
306 Lattice *editlatt = lt->editlatt->latt;
307 BPoint *bp;
308 int a;
309
310 bp = editlatt->def;
311
312 a = editlatt->pntsu * editlatt->pntsv * editlatt->pntsw;
313 while (a--) {
314 stats->totvert++;
315 if (bp->f1 & SELECT) {
316 stats->totvertsel++;
317 }
318 bp++;
319 }
320 }
321}
322
323static void stats_object_pose(const Object *ob, SceneStats *stats)
324{
325 if (ob->pose) {
326 bArmature *arm = static_cast<bArmature *>(ob->data);
327
328 LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
329 stats->totbone++;
330 if (pchan->bone && (pchan->bone->flag & BONE_SELECTED)) {
331 if (BKE_pose_is_bonecoll_visible(arm, pchan)) {
332 stats->totbonesel++;
333 }
334 }
335 }
336 }
337}
338
340{
342 return (ob->sculpt && ob->sculpt->bm);
343}
344
345static void stats_object_sculpt(const Object *ob, SceneStats *stats)
346{
347 const SculptSession *ss = ob->sculpt;
349 if (ss == nullptr || pbvh == nullptr) {
350 return;
351 }
352
353 switch (pbvh->type()) {
355 const Mesh &mesh = *static_cast<const Mesh *>(ob->data);
356 stats->totvertsculpt = mesh.verts_num;
357 stats->totfacesculpt = mesh.faces_num;
358 break;
359 }
361 stats->totvertsculpt = ob->sculpt->bm->totvert;
362 stats->tottri = ob->sculpt->bm->totface;
363 break;
367 break;
368 }
369}
370
371/* Statistics displayed in info header. Called regularly on scene changes. */
372static void stats_update(Depsgraph *depsgraph,
373 const Scene *scene,
374 ViewLayer *view_layer,
375 View3D *v3d_local,
376 SceneStats *stats)
377{
378 BKE_view_layer_synced_ensure(scene, view_layer);
379 const Object *ob = BKE_view_layer_active_object_get(view_layer);
380 const Object *obedit = BKE_view_layer_edit_object_get(view_layer);
381
382 memset(stats, 0x0, sizeof(*stats));
383
384 if (obedit && (ob->type != OB_GREASE_PENCIL)) {
385 /* Edit Mode. */
386 FOREACH_OBJECT_BEGIN (scene, view_layer, ob_iter) {
387 if (ob_iter->base_flag & BASE_ENABLED_AND_VISIBLE_IN_DEFAULT_VIEWPORT) {
388 if (ob_iter->mode & OB_MODE_EDIT) {
389 stats_object_edit(ob_iter, stats);
390 stats->totobjsel++;
391 }
392 else {
393 /* Skip hidden objects in local view that are not in edit-mode,
394 * an exception for edit-mode, in most other modes these would be considered hidden. */
395 if (v3d_local && !BKE_object_is_visible_in_viewport(v3d_local, ob_iter)) {
396 continue;
397 }
398 }
399 stats->totobj++;
400 }
401 }
403 }
404 else if (ob && (ob->mode & OB_MODE_POSE)) {
405 /* Pose Mode. */
406 FOREACH_OBJECT_BEGIN (scene, view_layer, ob_iter) {
407 if (ob_iter->base_flag & BASE_ENABLED_AND_VISIBLE_IN_DEFAULT_VIEWPORT) {
408 if (ob_iter->mode & OB_MODE_POSE) {
409 stats_object_pose(ob_iter, stats);
410 stats->totobjsel++;
411 }
412 else {
413 /* See comment for edit-mode. */
414 if (v3d_local && !BKE_object_is_visible_in_viewport(v3d_local, ob_iter)) {
415 continue;
416 }
417 }
418 stats->totobj++;
419 }
420 }
422 }
423 else if (ob && (ob->mode & OB_MODE_SCULPT)) {
424 /* Sculpt Mode. */
425 stats_object_sculpt(ob, stats);
426 }
427 else {
428 /* Objects. */
430 DEGObjectIterSettings deg_iter_settings{};
431 deg_iter_settings.depsgraph = depsgraph;
432 deg_iter_settings.flags = DEG_OBJECT_ITER_FOR_RENDER_ENGINE_FLAGS;
433 DEG_OBJECT_ITER_BEGIN (&deg_iter_settings, ob_iter) {
434 stats_object(ob_iter, v3d_local, stats, objects_gset);
435 }
437 BLI_gset_free(objects_gset, nullptr);
438 }
439}
440
442{
443 MEM_SAFE_FREE(view_layer->stats);
444
445 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
446 ViewLayer *view_layer_test = WM_window_get_active_view_layer(win);
447 if (view_layer != view_layer_test) {
448 continue;
449 }
450 const bScreen *screen = WM_window_get_active_screen(win);
451 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
452 if (area->spacetype == SPACE_VIEW3D) {
453 View3D *v3d = (View3D *)area->spacedata.first;
454 if (v3d->localvd) {
456 }
457 }
458 }
459 }
460}
461
462static bool format_stats(
463 Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d_local, SceneStatsFmt *stats_fmt)
464{
465 /* Create stats if they don't already exist. */
466 SceneStats **stats_p = (v3d_local) ? &v3d_local->runtime.local_stats : &view_layer->stats;
467 if (*stats_p == nullptr) {
468 /* Don't access dependency graph if interface is marked as locked. */
469 wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
470 if (wm->runtime->is_interface_locked) {
471 return false;
472 }
473 Depsgraph *depsgraph = BKE_scene_ensure_depsgraph(bmain, scene, view_layer);
474 *stats_p = (SceneStats *)MEM_mallocN(sizeof(SceneStats), __func__);
475 stats_update(depsgraph, scene, view_layer, v3d_local, *stats_p);
476 }
477
478 SceneStats *stats = *stats_p;
479
480 /* Generate formatted numbers. */
481#define SCENE_STATS_FMT_INT(_id) BLI_str_format_uint64_grouped(stats_fmt->_id, stats->_id)
482
483 SCENE_STATS_FMT_INT(totvert);
484 SCENE_STATS_FMT_INT(totvertsel);
485 SCENE_STATS_FMT_INT(totvertsculpt);
486
487 SCENE_STATS_FMT_INT(totedge);
488 SCENE_STATS_FMT_INT(totedgesel);
489
490 SCENE_STATS_FMT_INT(totface);
491 SCENE_STATS_FMT_INT(totfacesel);
492 SCENE_STATS_FMT_INT(totfacesculpt);
493
494 SCENE_STATS_FMT_INT(totbone);
495 SCENE_STATS_FMT_INT(totbonesel);
496
497 SCENE_STATS_FMT_INT(totobj);
498 SCENE_STATS_FMT_INT(totobjsel);
499
500 SCENE_STATS_FMT_INT(totlamp);
501 SCENE_STATS_FMT_INT(totlampsel);
502
503 SCENE_STATS_FMT_INT(tottri);
504 SCENE_STATS_FMT_INT(tottrisel);
505
506 SCENE_STATS_FMT_INT(totgplayer);
507 SCENE_STATS_FMT_INT(totgpframe);
508 SCENE_STATS_FMT_INT(totgpstroke);
509 SCENE_STATS_FMT_INT(totgppoint);
510
511#undef SCENE_STATS_FMT_INT
512 return true;
513}
514
515static void get_stats_string(char *info,
516 int len,
517 size_t *ofs,
518 const Scene *scene,
519 ViewLayer *view_layer,
520 SceneStatsFmt *stats_fmt)
521{
522 BKE_view_layer_synced_ensure(scene, view_layer);
524 Object *obedit = OBEDIT_FROM_OBACT(ob);
525 eObjectMode object_mode = ob ? (eObjectMode)ob->mode : OB_MODE_OBJECT;
526 LayerCollection *layer_collection = BKE_view_layer_active_collection_get(view_layer);
527
528 if (object_mode == OB_MODE_OBJECT) {
529 *ofs += BLI_snprintf_rlen(info + *ofs,
530 len - *ofs,
531 "%s | ",
532 BKE_collection_ui_name_get(layer_collection->collection));
533 }
534
535 if (ob) {
536 *ofs += BLI_snprintf_rlen(info + *ofs, len - *ofs, "%s | ", ob->id.name + 2);
537 }
538
539 if (obedit) {
540 if (BKE_keyblock_from_object(obedit)) {
541 *ofs += BLI_strncpy_rlen(info + *ofs, IFACE_("(Key) "), len - *ofs);
542 }
543
544 if (obedit->type == OB_MESH) {
545 *ofs += BLI_snprintf_rlen(info + *ofs,
546 len - *ofs,
547
548 IFACE_("Verts:%s/%s | Edges:%s/%s | Faces:%s/%s | Tris:%s"),
549 stats_fmt->totvertsel,
550 stats_fmt->totvert,
551 stats_fmt->totedgesel,
552 stats_fmt->totedge,
553 stats_fmt->totfacesel,
554 stats_fmt->totface,
555 stats_fmt->tottri);
556 }
557 else if (obedit->type == OB_ARMATURE) {
558 *ofs += BLI_snprintf_rlen(info + *ofs,
559 len - *ofs,
560
561 IFACE_("Joints:%s/%s | Bones:%s/%s"),
562 stats_fmt->totvertsel,
563 stats_fmt->totvert,
564 stats_fmt->totbonesel,
565 stats_fmt->totbone);
566 }
567 else {
568 *ofs += BLI_snprintf_rlen(info + *ofs,
569 len - *ofs,
570 IFACE_("Verts:%s/%s"),
571 stats_fmt->totvertsel,
572 stats_fmt->totvert);
573 }
574 }
575 else if (ob && (object_mode & OB_MODE_POSE)) {
576 *ofs += BLI_snprintf_rlen(
577 info + *ofs, len - *ofs, IFACE_("Bones:%s/%s"), stats_fmt->totbonesel, stats_fmt->totbone);
578 }
579 else if ((ob) && (ob->type == OB_GPENCIL_LEGACY)) {
580 *ofs += BLI_snprintf_rlen(info + *ofs,
581 len - *ofs,
582
583 IFACE_("Layers:%s | Frames:%s | Strokes:%s | Points:%s"),
584 stats_fmt->totgplayer,
585 stats_fmt->totgpframe,
586 stats_fmt->totgpstroke,
587 stats_fmt->totgppoint);
588 }
589 else if (ob && (object_mode & OB_MODE_SCULPT)) {
591 *ofs += BLI_snprintf_rlen(info + *ofs,
592 len - *ofs,
593
594 IFACE_("Verts:%s | Tris:%s"),
595 stats_fmt->totvertsculpt,
596 stats_fmt->tottri);
597 }
598 else {
599 *ofs += BLI_snprintf_rlen(info + *ofs,
600 len - *ofs,
601
602 IFACE_("Verts:%s | Faces:%s"),
603 stats_fmt->totvertsculpt,
604 stats_fmt->totfacesculpt);
605 }
606 }
607 else {
608 *ofs += BLI_snprintf_rlen(info + *ofs,
609 len - *ofs,
610
611 IFACE_("Verts:%s | Faces:%s | Tris:%s"),
612 stats_fmt->totvert,
613 stats_fmt->totface,
614 stats_fmt->tottri);
615 }
616
617 if (!STREQ(&stats_fmt->totobj[0], "0")) {
618 *ofs += BLI_snprintf_rlen(info + *ofs,
619 len - *ofs,
620
621 IFACE_(" | Objects:%s/%s"),
622 stats_fmt->totobjsel,
623 stats_fmt->totobj);
624 }
625}
626
628 Scene *scene,
629 ViewLayer *view_layer,
630 const char statusbar_flag)
631{
632 char formatted_mem[BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE];
633 size_t ofs = 0;
634 static char info[256];
635 int len = sizeof(info);
636
637 info[0] = '\0';
638
639 /* Scene statistics. */
640 if (statusbar_flag & STATUSBAR_SHOW_STATS) {
641 SceneStatsFmt stats_fmt;
642 if (format_stats(bmain, scene, view_layer, nullptr, &stats_fmt)) {
643 get_stats_string(info + ofs, len, &ofs, scene, view_layer, &stats_fmt);
644 }
645 }
646
647 /* Scene Duration. */
648 if (statusbar_flag & STATUSBAR_SHOW_SCENE_DURATION) {
649 if (info[0]) {
650 ofs += BLI_snprintf_rlen(info + ofs, len - ofs, " | ");
651 }
652 const int relative_current_frame = (scene->r.cfra - scene->r.sfra) + 1;
653 const int frame_count = (scene->r.efra - scene->r.sfra) + 1;
654 char timecode[32];
656 timecode, sizeof(timecode), -2, FRA2TIME(frame_count), FPS, U.timecode_style);
657 ofs += BLI_snprintf_rlen(info + ofs,
658 len - ofs,
659
660 IFACE_("Duration: %s (Frame %i/%i)"),
661 timecode,
662 relative_current_frame,
663 frame_count);
664 }
665
666 /* Memory status. */
667 if (statusbar_flag & STATUSBAR_SHOW_MEMORY) {
668 if (info[0]) {
669 ofs += BLI_snprintf_rlen(info + ofs, len - ofs, " | ");
670 }
672 BLI_str_format_byte_unit(formatted_mem, mem_in_use, false);
673 ofs += BLI_snprintf_rlen(info + ofs, len, IFACE_("Memory: %s"), formatted_mem);
674 }
675
676 /* GPU VRAM status. */
677 if ((statusbar_flag & STATUSBAR_SHOW_VRAM) && GPU_mem_stats_supported()) {
678 int gpu_free_mem_kb, gpu_tot_mem_kb;
679 GPU_mem_stats_get(&gpu_tot_mem_kb, &gpu_free_mem_kb);
680 float gpu_total_gb = gpu_tot_mem_kb / 1048576.0f;
681 float gpu_free_gb = gpu_free_mem_kb / 1048576.0f;
682 if (info[0]) {
683 ofs += BLI_snprintf_rlen(info + ofs, len - ofs, " | ");
684 }
685 if (gpu_free_mem_kb && gpu_tot_mem_kb) {
686 ofs += BLI_snprintf_rlen(info + ofs,
687 len - ofs,
688
689 IFACE_("VRAM: %.1f/%.1f GiB"),
690 gpu_total_gb - gpu_free_gb,
691 gpu_total_gb);
692 }
693 else {
694 /* Can only show amount of GPU VRAM available. */
695 ofs += BLI_snprintf_rlen(info + ofs, len - ofs, IFACE_("VRAM: %.1f GiB Free"), gpu_free_gb);
696 }
697 }
698
699 /* Blender version. */
700 if (statusbar_flag & STATUSBAR_SHOW_VERSION) {
701 if (info[0]) {
702 ofs += BLI_snprintf_rlen(info + ofs, len - ofs, " | ");
703 }
704 ofs += BLI_snprintf_rlen(
705 info + ofs, len - ofs, IFACE_("%s"), BKE_blender_version_string_compact());
706 }
707
708 return info;
709}
710
711const char *ED_info_statusbar_string(Main *bmain, Scene *scene, ViewLayer *view_layer)
712{
713 return ED_info_statusbar_string_ex(bmain, scene, view_layer, U.statusbar_flag);
714}
715
716const char *ED_info_statistics_string(Main *bmain, Scene *scene, ViewLayer *view_layer)
717{
718 const eUserpref_StatusBar_Flag statistics_status_bar_flag = STATUSBAR_SHOW_STATS |
722
723 return ED_info_statusbar_string_ex(bmain, scene, view_layer, statistics_status_bar_flag);
724}
725
726static void stats_row(int col1,
727 const char *key,
728 int col2,
729 const char *value1,
730 const char *value2,
731 int *y,
732 int height)
733{
734 *y -= height;
735 BLF_draw_default(col1, *y, 0.0f, key, 128);
736 char values[128];
737 SNPRINTF(values, (value2) ? "%s / %s" : "%s", value1, value2);
738 BLF_draw_default(col2, *y, 0.0f, values, sizeof(values));
739}
740
742 Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d_local, int x, int *y, int height)
743{
744 BLI_assert(v3d_local == nullptr || v3d_local->localvd != nullptr);
745 SceneStatsFmt stats_fmt;
746 if (!format_stats(bmain, scene, view_layer, v3d_local, &stats_fmt)) {
747 return;
748 }
749
750 BKE_view_layer_synced_ensure(scene, view_layer);
752 Object *obedit = OBEDIT_FROM_OBACT(ob);
753 eObjectMode object_mode = ob ? (eObjectMode)ob->mode : OB_MODE_OBJECT;
754 const int font_id = BLF_default();
755
756 /* Translated labels for each stat row. */
757 enum {
758 OBJ,
759 VERTS,
760 EDGES,
761 FACES,
762 TRIS,
763 JOINTS,
764 BONES,
765 LAYERS,
766 FRAMES,
767 STROKES,
768 POINTS,
769 LIGHTS,
770 MAX_LABELS_COUNT
771 };
772 char labels[MAX_LABELS_COUNT][64];
773
774 STRNCPY_UTF8(labels[OBJ], IFACE_("Objects"));
775 STRNCPY_UTF8(labels[VERTS], IFACE_("Vertices"));
776 STRNCPY_UTF8(labels[EDGES], IFACE_("Edges"));
777 STRNCPY_UTF8(labels[FACES], IFACE_("Faces"));
778 STRNCPY_UTF8(labels[TRIS], IFACE_("Triangles"));
779 STRNCPY_UTF8(labels[JOINTS], IFACE_("Joints"));
780 STRNCPY_UTF8(labels[BONES], IFACE_("Bones"));
781 STRNCPY_UTF8(labels[LAYERS], IFACE_("Layers"));
782 STRNCPY_UTF8(labels[FRAMES], IFACE_("Frames"));
783 STRNCPY_UTF8(labels[STROKES], IFACE_("Strokes"));
784 STRNCPY_UTF8(labels[POINTS], IFACE_("Points"));
785 STRNCPY_UTF8(labels[LIGHTS], IFACE_("Lights"));
786
787 int longest_label = 0;
788 for (int i = 0; i < MAX_LABELS_COUNT; ++i) {
789 longest_label = max_ii(longest_label, BLF_width(font_id, labels[i], sizeof(labels[i])));
790 }
791
792 int col1 = x;
793 int col2 = x + longest_label + (0.5f * U.widget_unit);
794
795 /* Add some extra margin above this section. */
796 *y -= (0.6f * height);
797
798 bool any_objects = !STREQ(&stats_fmt.totobj[0], "0");
799 bool any_selected = !STREQ(&stats_fmt.totobjsel[0], "0");
800
801 if (any_selected) {
802 stats_row(col1, labels[OBJ], col2, stats_fmt.totobjsel, stats_fmt.totobj, y, height);
803 }
804 else if (any_objects) {
805 stats_row(col1, labels[OBJ], col2, stats_fmt.totobj, nullptr, y, height);
806 /* Show scene totals if nothing is selected. */
807 stats_row(col1, labels[VERTS], col2, stats_fmt.totvert, nullptr, y, height);
808 stats_row(col1, labels[EDGES], col2, stats_fmt.totedge, nullptr, y, height);
809 stats_row(col1, labels[FACES], col2, stats_fmt.totface, nullptr, y, height);
810 stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, nullptr, y, height);
811 return;
812 }
813 else if (!(object_mode & OB_MODE_SCULPT)) {
814 /* No objects in scene. */
815 stats_row(col1, labels[OBJ], col2, stats_fmt.totobj, nullptr, y, height);
816 return;
817 }
818
819 if ((ob) && ELEM(ob->type, OB_GPENCIL_LEGACY, OB_GREASE_PENCIL)) {
820 stats_row(col1, labels[LAYERS], col2, stats_fmt.totgplayer, nullptr, y, height);
821 stats_row(col1, labels[FRAMES], col2, stats_fmt.totgpframe, nullptr, y, height);
822 stats_row(col1, labels[STROKES], col2, stats_fmt.totgpstroke, nullptr, y, height);
823 stats_row(col1, labels[POINTS], col2, stats_fmt.totgppoint, nullptr, y, height);
824 }
825 else if (obedit) {
826 if (obedit->type == OB_MESH) {
827 stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height);
828 stats_row(col1, labels[EDGES], col2, stats_fmt.totedgesel, stats_fmt.totedge, y, height);
829 stats_row(col1, labels[FACES], col2, stats_fmt.totfacesel, stats_fmt.totface, y, height);
830 stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, nullptr, y, height);
831 }
832 else if (obedit->type == OB_ARMATURE) {
833 stats_row(col1, labels[JOINTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height);
834 stats_row(col1, labels[BONES], col2, stats_fmt.totbonesel, stats_fmt.totbone, y, height);
835 }
836 else if (obedit->type != OB_FONT) {
837 stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height);
838 }
839 }
840 else if (ob && (object_mode & OB_MODE_SCULPT)) {
842 stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsculpt, nullptr, y, height);
843 stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, nullptr, y, height);
844 }
845 else {
846 stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsculpt, nullptr, y, height);
847 stats_row(col1, labels[FACES], col2, stats_fmt.totfacesculpt, nullptr, y, height);
848 }
849 }
850 else if (ob && (object_mode & OB_MODE_POSE)) {
851 stats_row(col1, labels[BONES], col2, stats_fmt.totbonesel, stats_fmt.totbone, y, height);
852 }
853 else if ((ob) && (ob->type == OB_LAMP)) {
854 stats_row(col1, labels[LIGHTS], col2, stats_fmt.totlampsel, stats_fmt.totlamp, y, height);
855 }
856 else if ((object_mode == OB_MODE_OBJECT) && ob && ELEM(ob->type, OB_MESH, OB_FONT)) {
857 /* Object mode with the active object a mesh or text object. */
858 stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height);
859 stats_row(col1, labels[EDGES], col2, stats_fmt.totedgesel, stats_fmt.totedge, y, height);
860 stats_row(col1, labels[FACES], col2, stats_fmt.totfacesel, stats_fmt.totface, y, height);
861 stats_row(col1, labels[TRIS], col2, stats_fmt.tottrisel, stats_fmt.tottri, y, height);
862 }
863}
Blender kernel action and pose functionality.
bool BKE_pose_is_bonecoll_visible(const bArmature *arm, const bPoseChannel *pchan) ATTR_WARN_UNUSED_RESULT
const char * BKE_blender_version_string_compact(void)
Definition blender.cc:144
const char * BKE_collection_ui_name_get(Collection *collection)
ListBase * BKE_curve_editNurbs_get(Curve *cu)
Definition curve.cc:398
Low-level operations for curves.
BMEditMesh * BKE_editmesh_from_object(Object *ob)
Return the BMEditMesh for a given object.
Definition editmesh.cc:63
Low-level operations for grease pencil.
KeyBlock * BKE_keyblock_from_object(Object *ob)
Definition key.cc:1905
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
LayerCollection * BKE_view_layer_active_collection_get(ViewLayer *view_layer)
#define FOREACH_OBJECT_END
Definition BKE_layer.hh:432
#define FOREACH_OBJECT_BEGIN(scene, view_layer, _instance)
Definition BKE_layer.hh:422
Object * BKE_view_layer_active_object_get(const ViewLayer *view_layer)
bool BKE_object_is_visible_in_viewport(const View3D *v3d, const Object *ob)
Object * BKE_view_layer_edit_object_get(const ViewLayer *view_layer)
General operations, lookup, etc. for blender objects.
Mesh * BKE_object_get_evaluated_mesh_no_subsurf(const Object *object_eval)
A BVH for high poly meshes.
int BKE_pbvh_get_grid_num_verts(const Object &object)
Definition pbvh.cc:1494
int BKE_pbvh_get_grid_num_faces(const Object &object)
Definition pbvh.cc:1502
Depsgraph * BKE_scene_ensure_depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer)
Definition scene.cc:3377
void BKE_subdiv_ccg_topology_counters(const SubdivCCG &subdiv_ccg, int &r_num_vertices, int &r_num_edges, int &r_num_faces, int &r_num_loops)
int BLF_default()
float BLF_width(int fontid, const char *str, size_t str_len, ResultBLF *r_info=nullptr) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2)
Definition blf.cc:791
void BLF_draw_default(float x, float y, float z, const char *str, size_t str_len) ATTR_NONNULL()
#define BLI_assert(a)
Definition BLI_assert.h:50
struct GSet GSet
Definition BLI_ghash.h:341
unsigned int BLI_ghashutil_ptrhash(const void *key)
GSet * BLI_gset_new(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:944
bool BLI_ghashutil_ptrcmp(const void *a, const void *b)
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.c:1034
bool BLI_gset_add(GSet *gs, void *key)
Definition BLI_ghash.c:966
#define LISTBASE_FOREACH(type, var, list)
MINLINE int max_ii(int a, int b)
MINLINE int poly_to_tri_count(int poly_count, int corner_count)
#define BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE
Definition BLI_string.h:28
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
void BLI_str_format_byte_unit(char dst[BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE], long long int bytes, bool base_10) ATTR_NONNULL(1)
Definition string.c:1192
#define BLI_STR_FORMAT_UINT64_GROUPED_SIZE
Definition BLI_string.h:22
size_t BLI_snprintf_rlen(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char char size_t BLI_strncpy_rlen(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
#define STRNCPY_UTF8(dst, src)
size_t BLI_timecode_string_from_time(char *str, size_t maxncpy, int brevity_level, float time_seconds, double fps, short timecode_style) ATTR_NONNULL()
Definition timecode.c:23
#define ENUM_OPERATORS(_type, _max)
#define ELEM(...)
#define STREQ(a, b)
#define IFACE_(msgid)
#define DEG_OBJECT_ITER_BEGIN(settings_, instance_)
#define DEG_OBJECT_ITER_END
#define DEG_OBJECT_ITER_FOR_RENDER_ENGINE_FLAGS
@ BONE_ROOTSEL
@ BONE_SELECTED
@ BONE_TIPSEL
@ BONE_CONNECTED
@ CU_BEZIER
@ BASE_ENABLED_AND_VISIBLE_IN_DEFAULT_VIEWPORT
eObjectMode
@ OB_MODE_EDIT
@ OB_MODE_SCULPT
@ OB_MODE_POSE
@ OB_MODE_OBJECT
@ OB_LATTICE
@ OB_MBALL
@ OB_SURF
@ OB_FONT
@ OB_GREASE_PENCIL
@ OB_ARMATURE
@ OB_LAMP
@ OB_MESH
@ OB_POINTCLOUD
@ OB_VOLUME
@ OB_CURVES_LEGACY
@ OB_GPENCIL_LEGACY
@ OB_CURVES
#define BASE_SELECTED(v3d, base)
#define OBEDIT_FROM_OBACT(ob)
#define FPS
#define FRA2TIME(a)
@ SPACE_VIEW3D
eUserpref_StatusBar_Flag
@ STATUSBAR_SHOW_STATS
@ STATUSBAR_SHOW_MEMORY
@ STATUSBAR_SHOW_VRAM
@ STATUSBAR_SHOW_SCENE_DURATION
@ STATUSBAR_SHOW_VERSION
void GPU_mem_stats_get(int *r_totalmem, int *r_freemem)
bool GPU_mem_stats_supported()
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
unsigned int U
Definition btGjkEpa3.h:78
int64_t size() const
Definition BLI_array.hh:245
#define SELECT
const Depsgraph * depsgraph
int len
#define SCENE_STATS_FMT_INT(_id)
static void stats_row(int col1, const char *key, int col2, const char *value1, const char *value2, int *y, int height)
static void stats_object_sculpt(const Object *ob, SceneStats *stats)
static void get_stats_string(char *info, int len, size_t *ofs, const Scene *scene, ViewLayer *view_layer, SceneStatsFmt *stats_fmt)
const char * ED_info_statusbar_string_ex(Main *bmain, Scene *scene, ViewLayer *view_layer, const char statusbar_flag)
const char * ED_info_statusbar_string(Main *bmain, Scene *scene, ViewLayer *view_layer)
const char * ED_info_statistics_string(Main *bmain, Scene *scene, ViewLayer *view_layer)
static void stats_update(Depsgraph *depsgraph, const Scene *scene, ViewLayer *view_layer, View3D *v3d_local, SceneStats *stats)
void ED_info_stats_clear(wmWindowManager *wm, ViewLayer *view_layer)
static void stats_object_pose(const Object *ob, SceneStats *stats)
static void stats_object(Object *ob, const View3D *v3d_local, SceneStats *stats, GSet *objects_gset)
static bool format_stats(Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d_local, SceneStatsFmt *stats_fmt)
static void stats_object_edit(Object *obedit, SceneStats *stats)
static bool stats_is_object_dynamic_topology_sculpt(const Object *ob)
static bool stats_mesheval(const Mesh *mesh_eval, bool is_selected, SceneStats *stats)
Definition info_stats.cc:96
void ED_info_draw_stats(Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d_local, int x, int *y, int height)
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
size_t(* MEM_get_memory_in_use)(void)
Definition mallocn.cc:62
static size_t mem_in_use
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:2846
_W64 unsigned int uintptr_t
Definition stdint.h:119
unsigned __int64 uint64_t
Definition stdint.h:90
blender::Array< std::array< BMLoop *, 3 > > looptris
int totvert
int totfacesel
int totedge
int totvertsel
int totedgesel
int totface
uint8_t f1
struct Lattice * latt
char name[66]
Definition DNA_ID.h:425
struct EditLatt * editlatt
struct BPoint * def
struct Collection * collection
void * first
ListBase wm
Definition BKE_main.hh:239
int corners_num
int edges_num
MeshRuntimeHandle * runtime
int faces_num
int verts_num
ListBase * editelems
short base_flag
struct bPose * pose
struct SculptSession * sculpt
char totobj[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:87
char totvertsel[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:81
char totedgesel[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:84
char totgpstroke[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:92
char totvert[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:81
char totfacesel[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:83
char totlamp[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:88
char totface[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:83
char totfacesculpt[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:85
char tottri[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:89
char totgplayer[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:90
char totbonesel[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:86
char totgpframe[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:91
char totlampsel[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:88
char totedge[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:84
char totbone[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:86
char tottrisel[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:89
char totobjsel[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:87
char totvertsculpt[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:82
char totgppoint[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:93
uint64_t totfacesculpt
Definition info_stats.cc:71
uint64_t totfacesel
Definition info_stats.cc:71
uint64_t tottri
Definition info_stats.cc:75
uint64_t totedgesel
Definition info_stats.cc:70
uint64_t totvert
Definition info_stats.cc:69
uint64_t totbone
Definition info_stats.cc:72
uint64_t totgpframe
Definition info_stats.cc:76
uint64_t totvertsel
Definition info_stats.cc:69
uint64_t totlamp
Definition info_stats.cc:74
uint64_t tottrisel
Definition info_stats.cc:75
uint64_t totface
Definition info_stats.cc:71
uint64_t totgplayer
Definition info_stats.cc:76
uint64_t totvertsculpt
Definition info_stats.cc:69
uint64_t totgppoint
Definition info_stats.cc:76
uint64_t totlampsel
Definition info_stats.cc:74
uint64_t totobj
Definition info_stats.cc:73
uint64_t totgpstroke
Definition info_stats.cc:76
uint64_t totedge
Definition info_stats.cc:70
uint64_t totbonesel
Definition info_stats.cc:72
uint64_t totobjsel
Definition info_stats.cc:73
struct SceneStats * local_stats
View3D_Runtime runtime
struct View3D * localvd
struct SceneStats * stats
ListBase * edbo
ListBase chanbase
WindowManagerRuntimeHandle * runtime
ViewLayer * WM_window_get_active_view_layer(const wmWindow *win)
bScreen * WM_window_get_active_screen(const wmWindow *win)