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