Blender V5.0
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
8
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"
17#include "DNA_lattice_types.h"
18#include "DNA_mesh_types.h"
19#include "DNA_meta_types.h"
21#include "DNA_scene_types.h"
22#include "DNA_space_enums.h"
24
25#include "BLF_api.hh"
26
27#include "BLI_array_utils.hh"
28#include "BLI_listbase.h"
29#include "BLI_math_geom.h"
30#include "BLI_span.hh"
31#include "BLI_string.h"
32#include "BLI_string_utf8.h"
33#include "BLI_timecode.h"
34#include "BLI_utildefines.h"
35
36#include "BLT_translation.hh"
37
38#include "BKE_action.hh"
39#include "BKE_armature.hh"
40#include "BKE_blender_version.h"
41#include "BKE_curve.hh"
42#include "BKE_curves.hh"
43#include "BKE_editmesh.hh"
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_paint_bvh.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 "GPU_capabilities.hh"
63
65
77
94
95static bool stats_mesheval(const Mesh *mesh_eval, bool is_selected, SceneStats *stats)
96{
97 if (mesh_eval == nullptr) {
98 return false;
99 }
100
101 int totvert, totedge, totface, totloop;
102
103 /* Get multires stats. */
104 if (const std::unique_ptr<SubdivCCG> &subdiv_ccg = mesh_eval->runtime->subdiv_ccg) {
105 BKE_subdiv_ccg_topology_counters(*subdiv_ccg, totvert, totedge, totface, totloop);
106 }
107 else {
108 /* Get CPU subdivided mesh if it exists. */
109 const SubsurfRuntimeData *subsurf_runtime_data = nullptr;
110 if (mesh_eval->runtime->mesh_eval) {
111 mesh_eval = mesh_eval->runtime->mesh_eval;
112 }
113 else {
114 subsurf_runtime_data = mesh_eval->runtime->subsurf_runtime_data;
115 }
116
117 /* Get GPU subdivision stats if they exist. If there is no 3D viewport or the mesh is
118 * hidden it will not be subdivided, fall back to unsubdivided in that case. */
119 if (subsurf_runtime_data && subsurf_runtime_data->has_gpu_subdiv &&
120 subsurf_runtime_data->stats_totvert)
121 {
122 totvert = subsurf_runtime_data->stats_totvert;
123 totedge = subsurf_runtime_data->stats_totedge;
124 totface = subsurf_runtime_data->stats_faces_num;
125 totloop = subsurf_runtime_data->stats_totloop;
126 }
127 else {
128 totvert = mesh_eval->verts_num;
129 totedge = mesh_eval->edges_num;
130 totface = mesh_eval->faces_num;
131 totloop = mesh_eval->corners_num;
132 }
133 }
134
135 stats->totvert += totvert;
136 stats->totedge += totedge;
137 stats->totface += totface;
138
139 const int tottri = poly_to_tri_count(totface, totloop);
140 stats->tottri += tottri;
141
142 if (is_selected) {
143 stats->totvertsel += totvert;
144 stats->totedgesel += totedge;
145 stats->totfacesel += totface;
146 stats->tottrisel += tottri;
147 }
148 return true;
149}
150
151static void stats_object(Object *ob,
152 const View3D *v3d_local,
153 SceneStats *stats,
154 GSet *objects_gset)
155{
157 return;
158 }
159
160 if (v3d_local && !BKE_object_is_visible_in_viewport(v3d_local, ob)) {
161 return;
162 }
163
164 const bool is_selected = (ob->base_flag & BASE_SELECTED) != 0;
165
166 stats->totobj++;
167 if (is_selected) {
168 stats->totobjsel++;
169 }
170
171 switch (ob->type) {
172 case OB_MESH: {
173 /* we assume evaluated mesh is already built, this strictly does stats now. */
174 const Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
175 if (!BLI_gset_add(objects_gset, (void *)mesh_eval)) {
176 break;
177 }
178 stats_mesheval(mesh_eval, is_selected, stats);
179 break;
180 }
181 case OB_LAMP:
182 stats->totlamp++;
183 if (is_selected) {
184 stats->totlampsel++;
185 }
186 break;
187 case OB_GREASE_PENCIL: {
188 if (!is_selected) {
189 break;
190 }
191
192 const GreasePencil *grease_pencil = static_cast<GreasePencil *>(ob->data);
193
194 for (const GreasePencilDrawingBase *drawing_base : grease_pencil->drawings()) {
195 const GreasePencilDrawing *drawing = reinterpret_cast<const GreasePencilDrawing *>(
196 drawing_base);
197 const blender::bke::CurvesGeometry &curves = drawing->wrap().strokes();
198
199 stats->totpoints += curves.points_num();
200 stats->totgpstroke += curves.curves_num();
201 }
202
203 for (const blender::bke::greasepencil::Layer *layer : grease_pencil->layers()) {
204 stats->totgpframe += layer->frames().size();
205 }
206
207 stats->totgplayer += grease_pencil->layers().size();
208 break;
209 }
210 case OB_CURVES: {
211 using namespace blender;
212 const Curves &curves_id = *static_cast<Curves *>(ob->data);
213 const bke::CurvesGeometry &curves = curves_id.geometry.wrap();
214 stats->totpoints += curves.points_num();
215 break;
216 }
217 case OB_POINTCLOUD:
218 case OB_VOLUME: {
219 break;
220 }
221 }
222}
223
224static void stats_object_edit(Object *obedit, SceneStats *stats)
225{
226 if (obedit->type == OB_MESH) {
228
229 stats->totvert += em->bm->totvert;
230 stats->totvertsel += em->bm->totvertsel;
231
232 stats->totedge += em->bm->totedge;
233 stats->totedgesel += em->bm->totedgesel;
234
235 stats->totface += em->bm->totface;
236 stats->totfacesel += em->bm->totfacesel;
237
238 stats->tottri += em->looptris.size();
239 }
240 else if (obedit->type == OB_ARMATURE) {
241 /* Armature Edit */
242 bArmature *arm = static_cast<bArmature *>(obedit->data);
243
244 LISTBASE_FOREACH (EditBone *, ebo, arm->edbo) {
245 stats->totbone++;
246
247 if ((ebo->flag & BONE_CONNECTED) && ebo->parent) {
248 stats->totvert--;
249 }
250
251 if (ebo->flag & BONE_TIPSEL) {
252 stats->totvertsel++;
253 }
254 if (ebo->flag & BONE_ROOTSEL) {
255 stats->totvertsel++;
256 }
257
258 if (ebo->flag & BONE_SELECTED) {
259 stats->totbonesel++;
260 }
261
262 /* if this is a connected child and its parent is being moved, remove our root */
263 if ((ebo->flag & BONE_CONNECTED) && (ebo->flag & BONE_ROOTSEL) && ebo->parent &&
264 (ebo->parent->flag & BONE_TIPSEL))
265 {
266 stats->totvertsel--;
267 }
268
269 stats->totvert += 2;
270 }
271 }
272 else if (ELEM(obedit->type, OB_CURVES_LEGACY, OB_SURF)) { /* OB_FONT has no cu->editnurb */
273 /* Curve Edit */
274 Curve *cu = static_cast<Curve *>(obedit->data);
275 BezTriple *bezt;
276 BPoint *bp;
277 int a;
279
280 LISTBASE_FOREACH (Nurb *, nu, nurbs) {
281 if (nu->type == CU_BEZIER) {
282 bezt = nu->bezt;
283 a = nu->pntsu;
284 while (a--) {
285 stats->totvert += 3;
286 if (bezt->f1 & SELECT) {
287 stats->totvertsel++;
288 }
289 if (bezt->f2 & SELECT) {
290 stats->totvertsel++;
291 }
292 if (bezt->f3 & SELECT) {
293 stats->totvertsel++;
294 }
295 bezt++;
296 }
297 }
298 else {
299 bp = nu->bp;
300 a = nu->pntsu * nu->pntsv;
301 while (a--) {
302 stats->totvert++;
303 if (bp->f1 & SELECT) {
304 stats->totvertsel++;
305 }
306 bp++;
307 }
308 }
309 }
310 }
311 else if (obedit->type == OB_MBALL) {
312 /* MetaBall Edit */
313 MetaBall *mball = static_cast<MetaBall *>(obedit->data);
314
315 LISTBASE_FOREACH (MetaElem *, ml, mball->editelems) {
316 stats->totvert++;
317 if (ml->flag & SELECT) {
318 stats->totvertsel++;
319 }
320 }
321 }
322 else if (obedit->type == OB_LATTICE) {
323 /* Lattice Edit */
324 Lattice *lt = static_cast<Lattice *>(obedit->data);
325 Lattice *editlatt = lt->editlatt->latt;
326 BPoint *bp;
327 int a;
328
329 bp = editlatt->def;
330
331 a = editlatt->pntsu * editlatt->pntsv * editlatt->pntsw;
332 while (a--) {
333 stats->totvert++;
334 if (bp->f1 & SELECT) {
335 stats->totvertsel++;
336 }
337 bp++;
338 }
339 }
340 else if (obedit->type == OB_CURVES) {
341 using namespace blender;
342 const Curves &curves_id = *static_cast<Curves *>(obedit->data);
343 const bke::CurvesGeometry &curves = curves_id.geometry.wrap();
344 const VArray<bool> selection = *curves.attributes().lookup_or_default<bool>(
345 ".selection", bke::AttrDomain::Point, true);
346 stats->totvertsel += array_utils::count_booleans(selection);
347 stats->totpoints += curves.points_num();
348 }
349 else if (obedit->type == OB_POINTCLOUD) {
350 using namespace blender;
351 PointCloud &pointcloud = *static_cast<PointCloud *>(obedit->data);
352 const VArray<bool> selection = *pointcloud.attributes().lookup_or_default<bool>(
353 ".selection", bke::AttrDomain::Point, true);
354 stats->totvertsel = array_utils::count_booleans(selection);
355 stats->totpoints = pointcloud.totpoint;
356 }
357}
358
359static void stats_object_pose(const Object *ob, SceneStats *stats)
360{
361 if (ob->pose) {
362 bArmature *arm = static_cast<bArmature *>(ob->data);
363
364 LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
365 stats->totbone++;
366 if ((pchan->flag & POSE_SELECTED)) {
367 if (BKE_pose_is_bonecoll_visible(arm, pchan)) {
368 stats->totbonesel++;
369 }
370 }
371 }
372 }
373}
374
376{
378 return (ob->sculpt && ob->sculpt->bm);
379}
380
381static void stats_object_sculpt(const Object *ob, SceneStats *stats)
382{
383 switch (ob->type) {
384 case OB_MESH: {
385 const SculptSession *ss = ob->sculpt;
387 if (ss == nullptr || pbvh == nullptr) {
388 return;
389 }
390
391 switch (pbvh->type()) {
393 const Mesh &mesh = *static_cast<const Mesh *>(ob->data);
394 stats->totvertsculpt = mesh.verts_num;
395 stats->totfacesculpt = mesh.faces_num;
396 break;
397 }
399 stats->totvertsculpt = ob->sculpt->bm->totvert;
400 stats->tottri = ob->sculpt->bm->totface;
401 break;
405 break;
406 }
407 break;
408 }
409 case OB_CURVES: {
410 const Curves &curves_id = *static_cast<Curves *>(ob->data);
411 const blender::bke::CurvesGeometry &curves = curves_id.geometry.wrap();
412 stats->totvertsculpt += curves.points_num();
413 break;
414 }
415 default:
416 break;
417 }
418}
419
420/* Statistics displayed in info header. Called regularly on scene changes. */
421static void stats_update(Depsgraph *depsgraph,
422 const Scene *scene,
423 ViewLayer *view_layer,
424 View3D *v3d_local,
425 SceneStats *stats)
426{
427 BKE_view_layer_synced_ensure(scene, view_layer);
428 const Object *ob = BKE_view_layer_active_object_get(view_layer);
429 const Object *obedit = BKE_view_layer_edit_object_get(view_layer);
430
431 memset(stats, 0x0, sizeof(*stats));
432
433 if (obedit && (ob->type != OB_GREASE_PENCIL)) {
434 /* Edit Mode. */
435 FOREACH_OBJECT_BEGIN (scene, view_layer, ob_iter) {
436 if (ob_iter->base_flag & BASE_ENABLED_AND_VISIBLE_IN_DEFAULT_VIEWPORT) {
437 if (ob_iter->mode & OB_MODE_EDIT) {
438 stats_object_edit(ob_iter, stats);
439 stats->totobjsel++;
440 }
441 else {
442 /* Skip hidden objects in local view that are not in edit-mode,
443 * an exception for edit-mode, in most other modes these would be considered hidden. */
444 if (v3d_local && !BKE_object_is_visible_in_viewport(v3d_local, ob_iter)) {
445 continue;
446 }
447 }
448 stats->totobj++;
449 }
450 }
452 }
453 else if (ob && (ob->mode & OB_MODE_POSE)) {
454 /* Pose Mode. */
455 FOREACH_OBJECT_BEGIN (scene, view_layer, ob_iter) {
456 if (ob_iter->base_flag & BASE_ENABLED_AND_VISIBLE_IN_DEFAULT_VIEWPORT) {
457 if (ob_iter->mode & OB_MODE_POSE) {
458 stats_object_pose(ob_iter, stats);
459 stats->totobjsel++;
460 }
461 else {
462 /* See comment for edit-mode. */
463 if (v3d_local && !BKE_object_is_visible_in_viewport(v3d_local, ob_iter)) {
464 continue;
465 }
466 }
467 stats->totobj++;
468 }
469 }
471 }
472 else if (ob && ELEM(ob->mode, OB_MODE_SCULPT, OB_MODE_SCULPT_CURVES)) {
473 /* Sculpt Mode. */
474 stats_object_sculpt(ob, stats);
475 }
476 else {
477 /* Objects. */
479 DEGObjectIterSettings deg_iter_settings{};
480 deg_iter_settings.depsgraph = depsgraph;
482 DEG_OBJECT_ITER_BEGIN (&deg_iter_settings, ob_iter) {
483 stats_object(ob_iter, v3d_local, stats, objects_gset);
484 }
486 BLI_gset_free(objects_gset, nullptr);
487 }
488}
489
491{
492 MEM_SAFE_FREE(view_layer->stats);
493
494 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
495 ViewLayer *view_layer_test = WM_window_get_active_view_layer(win);
496 if (view_layer != view_layer_test) {
497 continue;
498 }
499 const bScreen *screen = WM_window_get_active_screen(win);
500 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
501 if (area->spacetype == SPACE_VIEW3D) {
502 View3D *v3d = (View3D *)area->spacedata.first;
503 if (v3d->localvd) {
505 }
506 }
507 }
508 }
509}
510
515
516static bool format_stats(
517 Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d_local, SceneStatsFmt *stats_fmt)
518{
519 /* Create stats if they don't already exist. */
520 SceneStats **stats_p = (v3d_local) ? &v3d_local->runtime.local_stats : &view_layer->stats;
521 if (*stats_p == nullptr) {
522 /* Don't access dependency graph if interface is marked as locked. */
524 if (wm->runtime->is_interface_locked) {
525 return false;
526 }
527 Depsgraph *depsgraph = BKE_scene_ensure_depsgraph(bmain, scene, view_layer);
528 *stats_p = MEM_mallocN<SceneStats>(__func__);
529 stats_update(depsgraph, scene, view_layer, v3d_local, *stats_p);
530 }
531
532 SceneStats *stats = *stats_p;
533
534 /* Generate formatted numbers. */
535#define SCENE_STATS_FMT_INT(_id) BLI_str_format_uint64_grouped(stats_fmt->_id, stats->_id)
536
537 SCENE_STATS_FMT_INT(totvert);
538 SCENE_STATS_FMT_INT(totvertsel);
539 SCENE_STATS_FMT_INT(totvertsculpt);
540
541 SCENE_STATS_FMT_INT(totedge);
542 SCENE_STATS_FMT_INT(totedgesel);
543
544 SCENE_STATS_FMT_INT(totface);
545 SCENE_STATS_FMT_INT(totfacesel);
546 SCENE_STATS_FMT_INT(totfacesculpt);
547
548 SCENE_STATS_FMT_INT(totbone);
549 SCENE_STATS_FMT_INT(totbonesel);
550
551 SCENE_STATS_FMT_INT(totobj);
552 SCENE_STATS_FMT_INT(totobjsel);
553
554 SCENE_STATS_FMT_INT(totlamp);
555 SCENE_STATS_FMT_INT(totlampsel);
556
557 SCENE_STATS_FMT_INT(tottri);
558 SCENE_STATS_FMT_INT(tottrisel);
559
560 SCENE_STATS_FMT_INT(totgplayer);
561 SCENE_STATS_FMT_INT(totgpframe);
562 SCENE_STATS_FMT_INT(totgpstroke);
563
564 SCENE_STATS_FMT_INT(totpoints);
565
566#undef SCENE_STATS_FMT_INT
567 return true;
568}
569
570static void get_stats_string(char *info,
571 int len,
572 size_t *ofs,
573 const Scene *scene,
574 ViewLayer *view_layer,
575 SceneStatsFmt *stats_fmt)
576{
577 BKE_view_layer_synced_ensure(scene, view_layer);
579 eObjectMode object_mode = ob ? (eObjectMode)ob->mode : OB_MODE_OBJECT;
580 LayerCollection *layer_collection = BKE_view_layer_active_collection_get(view_layer);
581
582 if (object_mode == OB_MODE_OBJECT) {
583 *ofs += BLI_snprintf_utf8_rlen(info + *ofs,
584 len - *ofs,
585 "%s | ",
586 BKE_collection_ui_name_get(layer_collection->collection));
587 }
588
589 if (ob) {
590 *ofs += BLI_snprintf_utf8_rlen(info + *ofs, len - *ofs, "%s | ", ob->id.name + 2);
591 }
592
593 if ((ob) && (ob->type == OB_GREASE_PENCIL)) {
594 *ofs += BLI_snprintf_utf8_rlen(info + *ofs,
595 len - *ofs,
596
597 IFACE_("Layers:%s | Frames:%s | Strokes:%s | Points:%s"),
598 stats_fmt->totgplayer,
599 stats_fmt->totgpframe,
600 stats_fmt->totgpstroke,
601 stats_fmt->totpoints);
602 return;
603 }
604
605 if (ob && ob->mode == OB_MODE_EDIT) {
606 if (BKE_keyblock_from_object(ob)) {
607 *ofs += BLI_strncpy_utf8_rlen(info + *ofs, IFACE_("(Key) "), len - *ofs);
608 }
609
610 if (ob->type == OB_MESH) {
611 *ofs += BLI_snprintf_utf8_rlen(info + *ofs,
612 len - *ofs,
613
614 IFACE_("Verts:%s/%s | Edges:%s/%s | Faces:%s/%s | Tris:%s"),
615 stats_fmt->totvertsel,
616 stats_fmt->totvert,
617 stats_fmt->totedgesel,
618 stats_fmt->totedge,
619 stats_fmt->totfacesel,
620 stats_fmt->totface,
621 stats_fmt->tottri);
622 }
623 else if (ob->type == OB_ARMATURE) {
624 *ofs += BLI_snprintf_utf8_rlen(info + *ofs,
625 len - *ofs,
626
627 IFACE_("Joints:%s/%s | Bones:%s/%s"),
628 stats_fmt->totvertsel,
629 stats_fmt->totvert,
630 stats_fmt->totbonesel,
631 stats_fmt->totbone);
632 }
633 else if (ob->type == OB_CURVES) {
634 *ofs += BLI_snprintf_utf8_rlen(info + *ofs,
635 len - *ofs,
636 IFACE_("Points:%s/%s"),
637 stats_fmt->totvertsel,
638 stats_fmt->totpoints);
639 }
640 else if (ob->type == OB_POINTCLOUD) {
641 *ofs += BLI_snprintf_utf8_rlen(info + *ofs,
642 len - *ofs,
643 IFACE_("Points:%s/%s"),
644 stats_fmt->totvertsel,
645 stats_fmt->totpoints);
646 }
647 else {
648 *ofs += BLI_snprintf_utf8_rlen(info + *ofs,
649 len - *ofs,
650 IFACE_("Verts:%s/%s"),
651 stats_fmt->totvertsel,
652 stats_fmt->totvert);
653 }
654 }
655 else if (ob && (object_mode & OB_MODE_POSE)) {
657 info + *ofs, len - *ofs, IFACE_("Bones:%s/%s"), stats_fmt->totbonesel, stats_fmt->totbone);
658 }
659 else if (ob && (ob->type == OB_CURVES)) {
660 const char *count = (object_mode == OB_MODE_SCULPT_CURVES) ? stats_fmt->totvertsculpt :
661 stats_fmt->totpoints;
662 *ofs += BLI_snprintf_utf8_rlen(info + *ofs, len - *ofs, IFACE_("Points:%s"), count);
663 }
664 else if (ob && (object_mode & OB_MODE_SCULPT)) {
666 *ofs += BLI_snprintf_utf8_rlen(info + *ofs,
667 len - *ofs,
668
669 IFACE_("Verts:%s | Tris:%s"),
670 stats_fmt->totvertsculpt,
671 stats_fmt->tottri);
672 }
673 else {
674 *ofs += BLI_snprintf_utf8_rlen(info + *ofs,
675 len - *ofs,
676
677 IFACE_("Verts:%s | Faces:%s"),
678 stats_fmt->totvertsculpt,
679 stats_fmt->totfacesculpt);
680 }
681 }
682 else {
683 *ofs += BLI_snprintf_utf8_rlen(info + *ofs,
684 len - *ofs,
685
686 IFACE_("Verts:%s | Faces:%s | Tris:%s"),
687 stats_fmt->totvert,
688 stats_fmt->totface,
689 stats_fmt->tottri);
690 }
691
692 if (!STREQ(&stats_fmt->totobj[0], "0")) {
693 *ofs += BLI_snprintf_utf8_rlen(info + *ofs,
694 len - *ofs,
695
696 IFACE_(" | Objects:%s/%s"),
697 stats_fmt->totobjsel,
698 stats_fmt->totobj);
699 }
700}
701
703 Scene *scene,
704 ViewLayer *view_layer,
705 const char statusbar_flag)
706{
707 char formatted_mem[BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE];
708 size_t ofs = 0;
709 static char info[256];
710 int len = sizeof(info);
711
712 info[0] = '\0';
713
714 /* Scene statistics. */
715 if (statusbar_flag & STATUSBAR_SHOW_STATS) {
716 SceneStatsFmt stats_fmt;
717 if (format_stats(bmain, scene, view_layer, nullptr, &stats_fmt)) {
718 get_stats_string(info + ofs, len, &ofs, scene, view_layer, &stats_fmt);
719 }
720 }
721
722 /* Scene Duration. */
723 if (statusbar_flag & STATUSBAR_SHOW_SCENE_DURATION) {
724 if (info[0]) {
725 ofs += BLI_snprintf_utf8_rlen(info + ofs, len - ofs, " | ");
726 }
727 const int relative_current_frame = (scene->r.cfra - scene->r.sfra) + 1;
728 const int frame_count = (scene->r.efra - scene->r.sfra) + 1;
729 char timecode[32];
731 sizeof(timecode),
732 -2,
733 FRA2TIME(frame_count),
734 scene->frames_per_second(),
735 U.timecode_style);
736 ofs += BLI_snprintf_utf8_rlen(info + ofs,
737 len - ofs,
738
739 IFACE_("Duration: %s (Frame %i/%i)"),
740 timecode,
741 relative_current_frame,
742 frame_count);
743 }
744
745 /* Memory status. */
746 if (statusbar_flag & STATUSBAR_SHOW_MEMORY) {
747 if (info[0]) {
748 ofs += BLI_snprintf_utf8_rlen(info + ofs, len - ofs, " | ");
749 }
750 uintptr_t mem_in_use = MEM_get_memory_in_use();
751 BLI_str_format_byte_unit(formatted_mem, mem_in_use, false);
752 ofs += BLI_snprintf_utf8_rlen(info + ofs, len, IFACE_("Memory: %s"), formatted_mem);
753 }
754
755 /* GPU VRAM status. */
756 if ((statusbar_flag & STATUSBAR_SHOW_VRAM) && GPU_mem_stats_supported()) {
757 int gpu_free_mem_kb, gpu_tot_mem_kb;
758 GPU_mem_stats_get(&gpu_tot_mem_kb, &gpu_free_mem_kb);
759 float gpu_total_gb = gpu_tot_mem_kb / 1048576.0f;
760 float gpu_free_gb = gpu_free_mem_kb / 1048576.0f;
761 if (info[0]) {
762 ofs += BLI_snprintf_utf8_rlen(info + ofs, len - ofs, " | ");
763 }
764 if (gpu_free_mem_kb && gpu_tot_mem_kb) {
765 ofs += BLI_snprintf_utf8_rlen(info + ofs,
766 len - ofs,
767
768 IFACE_("VRAM: %.1f/%.1f GiB"),
769 gpu_total_gb - gpu_free_gb,
770 gpu_total_gb);
771 }
772 else {
773 /* Can only show amount of GPU VRAM available. */
775 info + ofs, len - ofs, IFACE_("VRAM: %.1f GiB Free"), gpu_free_gb);
776 }
777 }
778
779 /* Blender version. */
780 if (statusbar_flag & STATUSBAR_SHOW_VERSION) {
781 if (info[0]) {
782 ofs += BLI_snprintf_utf8_rlen(info + ofs, len - ofs, " | ");
783 }
785 info + ofs, len - ofs, IFACE_("%s"), BKE_blender_version_string_compact());
786 }
787
788 return info;
789}
790
791const char *ED_info_statusbar_string(Main *bmain, Scene *scene, ViewLayer *view_layer)
792{
793 return ED_info_statusbar_string_ex(bmain, scene, view_layer, U.statusbar_flag);
794}
795
796const char *ED_info_statistics_string(Main *bmain, Scene *scene, ViewLayer *view_layer)
797{
798 const eUserpref_StatusBar_Flag statistics_status_bar_flag = STATUSBAR_SHOW_STATS |
802
803 return ED_info_statusbar_string_ex(bmain, scene, view_layer, statistics_status_bar_flag);
804}
805
806static void stats_row(int col1,
807 const char *key,
808 int col2,
809 const char *value1,
810 const char *value2,
811 int *y,
812 int height)
813{
814 *y -= height;
815 BLF_draw_default(col1, *y, 0.0f, key, 128);
816 char values[128];
817 SNPRINTF_UTF8(values, (value2) ? "%s / %s" : "%s", value1, value2);
818 BLF_draw_default(col2, *y, 0.0f, values, sizeof(values));
819}
820
822 Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d_local, int x, int *y, int height)
823{
824 BLI_assert(v3d_local == nullptr || v3d_local->localvd != nullptr);
825 SceneStatsFmt stats_fmt;
826 if (!format_stats(bmain, scene, view_layer, v3d_local, &stats_fmt)) {
827 return;
828 }
829
830 BKE_view_layer_synced_ensure(scene, view_layer);
832 eObjectMode object_mode = ob ? (eObjectMode)ob->mode : OB_MODE_OBJECT;
833 const int font_id = BLF_default();
834
835 /* Translated labels for each stat row. */
836 enum {
837 OBJ,
838 VERTS,
839 EDGES,
840 FACES,
841 TRIS,
842 JOINTS,
843 BONES,
844 LAYERS,
845 FRAMES,
846 STROKES,
847 POINTS,
848 LIGHTS,
849 MAX_LABELS_COUNT
850 };
851 char labels[MAX_LABELS_COUNT][64];
852
853 STRNCPY_UTF8(labels[OBJ], IFACE_("Objects"));
854 STRNCPY_UTF8(labels[VERTS], IFACE_("Vertices"));
855 STRNCPY_UTF8(labels[EDGES], IFACE_("Edges"));
856 STRNCPY_UTF8(labels[FACES], IFACE_("Faces"));
857 STRNCPY_UTF8(labels[TRIS], IFACE_("Triangles"));
858 STRNCPY_UTF8(labels[JOINTS], IFACE_("Joints"));
859 STRNCPY_UTF8(labels[BONES], IFACE_("Bones"));
860 STRNCPY_UTF8(labels[LAYERS], IFACE_("Layers"));
861 STRNCPY_UTF8(labels[FRAMES], IFACE_("Frames"));
862 STRNCPY_UTF8(labels[STROKES], IFACE_("Strokes"));
863 STRNCPY_UTF8(labels[POINTS], IFACE_("Points"));
864 STRNCPY_UTF8(labels[LIGHTS], IFACE_("Lights"));
865
866 int longest_label = 0;
867 for (int i = 0; i < MAX_LABELS_COUNT; ++i) {
868 longest_label = max_ii(longest_label, BLF_width(font_id, labels[i], sizeof(labels[i])));
869 }
870
871 int col1 = x;
872 int col2 = x + longest_label + (0.5f * U.widget_unit);
873
874 /* Add some extra margin above this section. */
875 *y -= (0.6f * height);
876
877 bool any_objects = !STREQ(&stats_fmt.totobj[0], "0");
878 bool any_selected = !STREQ(&stats_fmt.totobjsel[0], "0");
879
880 if (any_selected) {
881 stats_row(col1, labels[OBJ], col2, stats_fmt.totobjsel, stats_fmt.totobj, y, height);
882 }
883 else if (any_objects) {
884 stats_row(col1, labels[OBJ], col2, stats_fmt.totobj, nullptr, y, height);
885 /* Show scene totals if nothing is selected. */
886 stats_row(col1, labels[VERTS], col2, stats_fmt.totvert, nullptr, y, height);
887 stats_row(col1, labels[EDGES], col2, stats_fmt.totedge, nullptr, y, height);
888 stats_row(col1, labels[FACES], col2, stats_fmt.totface, nullptr, y, height);
889 stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, nullptr, y, height);
890 return;
891 }
892 else if (!ELEM(object_mode, OB_MODE_SCULPT, OB_MODE_SCULPT_CURVES)) {
893 /* No objects in scene. */
894 stats_row(col1, labels[OBJ], col2, stats_fmt.totobj, nullptr, y, height);
895 return;
896 }
897
898 if ((ob) && ob->type == OB_GREASE_PENCIL) {
899 stats_row(col1, labels[LAYERS], col2, stats_fmt.totgplayer, nullptr, y, height);
900 stats_row(col1, labels[FRAMES], col2, stats_fmt.totgpframe, nullptr, y, height);
901 stats_row(col1, labels[STROKES], col2, stats_fmt.totgpstroke, nullptr, y, height);
902 stats_row(col1, labels[POINTS], col2, stats_fmt.totpoints, nullptr, y, height);
903 }
904 else if (ob && ob->mode == OB_MODE_EDIT) {
905 if (ob->type == OB_MESH) {
906 stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height);
907 stats_row(col1, labels[EDGES], col2, stats_fmt.totedgesel, stats_fmt.totedge, y, height);
908 stats_row(col1, labels[FACES], col2, stats_fmt.totfacesel, stats_fmt.totface, y, height);
909 stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, nullptr, y, height);
910 }
911 else if (ob->type == OB_ARMATURE) {
912 stats_row(col1, labels[JOINTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height);
913 stats_row(col1, labels[BONES], col2, stats_fmt.totbonesel, stats_fmt.totbone, y, height);
914 }
915 else if (ob->type == OB_CURVES) {
916 stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totpoints, y, height);
917 }
918 else if (ob->type == OB_POINTCLOUD) {
919 stats_row(col1, labels[POINTS], col2, stats_fmt.totvertsel, stats_fmt.totpoints, y, height);
920 }
921 else if (ob->type != OB_FONT) {
922 stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height);
923 }
924 }
925 else if (ob && (object_mode & OB_MODE_SCULPT)) {
927 stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsculpt, nullptr, y, height);
928 stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, nullptr, y, height);
929 }
930 else {
931 stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsculpt, nullptr, y, height);
932 stats_row(col1, labels[FACES], col2, stats_fmt.totfacesculpt, nullptr, y, height);
933 }
934 }
935 else if (ob && (object_mode & OB_MODE_SCULPT_CURVES)) {
936 stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsculpt, nullptr, y, height);
937 }
938 else if (ob && (object_mode & OB_MODE_POSE)) {
939 stats_row(col1, labels[BONES], col2, stats_fmt.totbonesel, stats_fmt.totbone, y, height);
940 }
941 else if ((ob) && (ob->type == OB_LAMP)) {
942 stats_row(col1, labels[LIGHTS], col2, stats_fmt.totlampsel, stats_fmt.totlamp, y, height);
943 }
944 else if ((object_mode == OB_MODE_OBJECT) && ob && ELEM(ob->type, OB_MESH, OB_FONT)) {
945 /* Object mode with the active object a mesh or text object. */
946 stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height);
947 stats_row(col1, labels[EDGES], col2, stats_fmt.totedgesel, stats_fmt.totedge, y, height);
948 stats_row(col1, labels[FACES], col2, stats_fmt.totfacesel, stats_fmt.totface, y, height);
949 stats_row(col1, labels[TRIS], col2, stats_fmt.tottrisel, stats_fmt.tottri, y, height);
950 }
951}
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:151
const char * BKE_collection_ui_name_get(Collection *collection)
ListBase * BKE_curve_editNurbs_get(Curve *cu)
Definition curve.cc:419
Low-level operations for curves.
BMEditMesh * BKE_editmesh_from_object(Object *ob)
Return the BMEditMesh for a given object.
Definition editmesh.cc:61
Low-level operations for grease pencil.
KeyBlock * BKE_keyblock_from_object(Object *ob)
Definition key.cc:1889
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:1675
int BKE_pbvh_get_grid_num_faces(const Object &object)
Definition pbvh.cc:1683
Depsgraph * BKE_scene_ensure_depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer)
Definition scene.cc:3416
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:802
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:46
struct GSet GSet
Definition BLI_ghash.h:337
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.cc:944
bool BLI_ghashutil_ptrcmp(const void *a, const void *b)
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
bool BLI_gset_add(GSet *gs, void *key)
Definition BLI_ghash.cc: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:31
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.cc:1207
#define BLI_STR_FORMAT_UINT64_GROUPED_SIZE
Definition BLI_string.h:22
#define SNPRINTF_UTF8(dst, format,...)
char size_t BLI_strncpy_utf8_rlen(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
size_t BLI_snprintf_utf8_rlen(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) 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.cc:22
#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
@ POSE_SELECTED
@ 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_SCULPT_CURVES
@ 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_CURVES
#define BASE_SELECTED(v3d, base)
#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)
#define U
BPy_StructRNA * depsgraph
unsigned long long int uint64_t
int64_t size() const
Definition BLI_array.hh:256
AttributeSet attributes
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, AttrType data_type, const void *default_value=nullptr) const
AttributeAccessor attributes() const
#define SELECT
#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)
void ED_view3d_local_stats_free(View3D *v3d)
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:95
void ED_info_draw_stats(Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d_local, int x, int *y, int height)
int count
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
size_t(* MEM_get_memory_in_use)(void)
Definition mallocn.cc:70
static size_t mem_in_use
int64_t count_booleans(const VArray< bool > &varray)
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:3052
blender::Array< std::array< BMLoop *, 3 > > looptris
int totvert
int totfacesel
int totedge
int totvertsel
int totedgesel
int totface
uint8_t f1
CurvesGeometry geometry
struct Lattice * latt
char name[258]
Definition DNA_ID.h:432
struct EditLatt * editlatt
struct BPoint * def
struct Collection * collection
void * first
ListBase wm
Definition BKE_main.hh:307
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:86
char totvertsel[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:80
char totedgesel[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:83
char totgpstroke[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:91
char totvert[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:80
char totfacesel[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:82
char totlamp[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:87
char totface[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:82
char totfacesculpt[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:84
char totpoints[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:92
char tottri[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:88
char totgplayer[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:89
char totbonesel[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:85
char totgpframe[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:90
char totlampsel[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:87
char totedge[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:83
char totbone[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:85
char tottrisel[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:88
char totobjsel[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:86
char totvertsculpt[BLI_STR_FORMAT_UINT64_GROUPED_SIZE]
Definition info_stats.cc:81
uint64_t totfacesculpt
Definition info_stats.cc:69
uint64_t totfacesel
Definition info_stats.cc:69
uint64_t tottri
Definition info_stats.cc:73
uint64_t totedgesel
Definition info_stats.cc:68
uint64_t totvert
Definition info_stats.cc:67
uint64_t totbone
Definition info_stats.cc:70
uint64_t totgpframe
Definition info_stats.cc:74
uint64_t totvertsel
Definition info_stats.cc:67
uint64_t totlamp
Definition info_stats.cc:72
uint64_t tottrisel
Definition info_stats.cc:73
uint64_t totface
Definition info_stats.cc:69
uint64_t totgplayer
Definition info_stats.cc:74
uint64_t totvertsculpt
Definition info_stats.cc:67
uint64_t totpoints
Definition info_stats.cc:75
uint64_t totlampsel
Definition info_stats.cc:72
uint64_t totobj
Definition info_stats.cc:71
uint64_t totgpstroke
Definition info_stats.cc:74
uint64_t totedge
Definition info_stats.cc:68
uint64_t totbonesel
Definition info_stats.cc:70
uint64_t totobjsel
Definition info_stats.cc:71
struct RenderData r
struct SceneStats * local_stats
View3D_Runtime runtime
struct View3D * localvd
struct SceneStats * stats
ListBase * edbo
ListBase chanbase
ListBase areabase
i
Definition text_draw.cc:230
uint len
ViewLayer * WM_window_get_active_view_layer(const wmWindow *win)
bScreen * WM_window_get_active_screen(const wmWindow *win)