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