976769752f9692271f76f5f84786c908cb4ed2b3
[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_mesh_types.h"
38 #include "DNA_meta_types.h"
39 #include "DNA_scene_types.h"
40
41 #include "BLI_utildefines.h"
42 #include "BLI_math.h"
43
44 #include "BLF_translation.h"
45
46 #include "BKE_anim.h"
47 #include "BKE_blender.h"
48 #include "BKE_curve.h"
49 #include "BKE_displist.h"
50 #include "BKE_DerivedMesh.h"
51 #include "BKE_key.h"
52 #include "BKE_mesh.h"
53 #include "BKE_paint.h"
54 #include "BKE_particle.h"
55 #include "BKE_tessmesh.h"
56
57 #include "ED_info.h"
58 #include "ED_armature.h"
59 #include "ED_mesh.h"
60
61
62 typedef struct SceneStats {
63         int totvert, totvertsel;
64         int totedge, totedgesel;
65         int totface, totfacesel;
66         int totbone, totbonesel;
67         int totobj,  totobjsel;
68         int totlamp, totlampsel; 
69         int tottri, totmesh;
70
71         char infostr[512];
72 } SceneStats;
73
74 static void stats_object(Object *ob, int sel, int totob, SceneStats *stats)
75 {
76         switch (ob->type) {
77                 case OB_MESH:
78                 {
79                         /* we assume derivedmesh is already built, this strictly does stats now. */
80                         DerivedMesh *dm = ob->derivedFinal;
81                         int totvert, totedge, totface, totloop;
82
83                         stats->totmesh += totob;
84
85                         if (dm) {
86                                 totvert = dm->getNumVerts(dm);
87                                 totedge = dm->getNumEdges(dm);
88                                 totface = dm->getNumPolys(dm);
89                                 totloop = dm->getNumLoops(dm);
90
91                                 stats->totvert += totvert * totob;
92                                 stats->totedge += totedge * totob;
93                                 stats->totface += totface * totob;
94                                 stats->tottri  += poly_to_tri_count(totface, totloop) * totob;
95
96                                 if (sel) {
97                                         stats->totvertsel += totvert;
98                                         stats->totfacesel += totface;
99                                 }
100                         }
101                         break;
102                 }
103                 case OB_LAMP:
104                         stats->totlamp += totob;
105                         if (sel) {
106                                 stats->totlampsel += totob;
107                         }
108                         break;
109                 case OB_SURF:
110                 case OB_CURVE:
111                 case OB_FONT:
112                 case OB_MBALL:
113                 {
114                         int totv = 0, totf = 0, tottri = 0;
115
116                         if (ob->disp.first)
117                                 BKE_displist_count(&ob->disp, &totv, &totf, &tottri);
118
119                         totv   *= totob;
120                         totf   *= totob;
121                         tottri *= totob;
122
123                         stats->totvert += totv;
124                         stats->totface += totf;
125                         stats->tottri  += tottri;
126
127                         if (sel) {
128                                 stats->totvertsel += totv;
129                                 stats->totfacesel += totf;
130                         }
131                         break;
132                 }
133         }
134 }
135
136 static void stats_object_edit(Object *obedit, SceneStats *stats)
137 {
138         if (obedit->type == OB_MESH) {
139                 BMEditMesh *em = BMEdit_FromObject(obedit);
140
141                 stats->totvert = em->bm->totvert;
142                 stats->totvertsel = em->bm->totvertsel;
143                 
144                 stats->totedge = em->bm->totedge;
145                 stats->totedgesel = em->bm->totedgesel;
146                 
147                 stats->totface = em->bm->totface;
148                 stats->totfacesel = em->bm->totfacesel;
149
150                 stats->tottri = em->tottri;
151         }
152         else if (obedit->type == OB_ARMATURE) {
153                 /* Armature Edit */
154                 bArmature *arm = obedit->data;
155                 EditBone *ebo;
156
157                 for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
158                         stats->totbone++;
159                         
160                         if ((ebo->flag & BONE_CONNECTED) && ebo->parent)
161                                 stats->totvert--;
162                         
163                         if (ebo->flag & BONE_TIPSEL)
164                                 stats->totvertsel++;
165                         if (ebo->flag & BONE_ROOTSEL)
166                                 stats->totvertsel++;
167                         
168                         if (ebo->flag & BONE_SELECTED) stats->totbonesel++;
169
170                         /* if this is a connected child and it's parent is being moved, remove our root */
171                         if ((ebo->flag & BONE_CONNECTED) && (ebo->flag & BONE_ROOTSEL) &&
172                             ebo->parent && (ebo->parent->flag & BONE_TIPSEL))
173                         {
174                                 stats->totvertsel--;
175                         }
176
177                         stats->totvert += 2;
178                 }
179         }
180         else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) { /* OB_FONT has no cu->editnurb */
181                 /* Curve Edit */
182                 Curve *cu = obedit->data;
183                 Nurb *nu;
184                 BezTriple *bezt;
185                 BPoint *bp;
186                 int a;
187                 ListBase *nurbs = BKE_curve_editNurbs_get(cu);
188
189                 for (nu = nurbs->first; nu; nu = nu->next) {
190                         if (nu->type == CU_BEZIER) {
191                                 bezt = nu->bezt;
192                                 a = nu->pntsu;
193                                 while (a--) {
194                                         stats->totvert += 3;
195                                         if (bezt->f1) stats->totvertsel++;
196                                         if (bezt->f2) stats->totvertsel++;
197                                         if (bezt->f3) stats->totvertsel++;
198                                         bezt++;
199                                 }
200                         }
201                         else {
202                                 bp = nu->bp;
203                                 a = nu->pntsu * nu->pntsv;
204                                 while (a--) {
205                                         stats->totvert++;
206                                         if (bp->f1 & SELECT) stats->totvertsel++;
207                                         bp++;
208                                 }
209                         }
210                 }
211         }
212         else if (obedit->type == OB_MBALL) {
213                 /* MetaBall Edit */
214                 MetaBall *mball = obedit->data;
215                 MetaElem *ml;
216                 
217                 for (ml = mball->editelems->first; ml; ml = ml->next) {
218                         stats->totvert++;
219                         if (ml->flag & SELECT) stats->totvertsel++;
220                 }
221         }
222         else if (obedit->type == OB_LATTICE) {
223                 /* Lattice Edit */
224                 Lattice *lt = obedit->data;
225                 Lattice *editlatt = lt->editlatt->latt;
226                 BPoint *bp;
227                 int a;
228
229                 bp = editlatt->def;
230                 
231                 a = editlatt->pntsu * editlatt->pntsv * editlatt->pntsw;
232                 while (a--) {
233                         stats->totvert++;
234                         if (bp->f1 & SELECT) stats->totvertsel++;
235                         bp++;
236                 }
237         }
238 }
239
240 static void stats_object_pose(Object *ob, SceneStats *stats)
241 {
242         if (ob->pose) {
243                 bArmature *arm = ob->data;
244                 bPoseChannel *pchan;
245
246                 for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
247                         stats->totbone++;
248                         if (pchan->bone && (pchan->bone->flag & BONE_SELECTED))
249                                 if (pchan->bone->layer & arm->layer)
250                                         stats->totbonesel++;
251                 }
252         }
253 }
254
255 static void stats_object_sculpt_dynamic_topology(Object *ob, SceneStats *stats)
256 {
257         stats->totvert = ob->sculpt->bm->totvert;
258         stats->tottri = ob->sculpt->bm->totface;
259 }
260
261 static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats)
262 {
263         if (base->flag & SELECT) stats->totobjsel++;
264
265         if (ob->transflag & OB_DUPLIPARTS) {
266                 /* Dupli Particles */
267                 ParticleSystem *psys;
268                 ParticleSettings *part;
269
270                 for (psys = ob->particlesystem.first; psys; psys = psys->next) {
271                         part = psys->part;
272
273                         if (part->draw_as == PART_DRAW_OB && part->dup_ob) {
274                                 int tot = count_particles(psys);
275                                 stats_object(part->dup_ob, 0, tot, stats);
276                         }
277                         else if (part->draw_as == PART_DRAW_GR && part->dup_group) {
278                                 GroupObject *go;
279                                 int tot, totgroup = 0, cur = 0;
280                                 
281                                 for (go = part->dup_group->gobject.first; go; go = go->next)
282                                         totgroup++;
283
284                                 for (go = part->dup_group->gobject.first; go; go = go->next) {
285                                         tot = count_particles_mod(psys, totgroup, cur);
286                                         stats_object(go->ob, 0, tot, stats);
287                                         cur++;
288                                 }
289                         }
290                 }
291                 
292                 stats_object(ob, base->flag & SELECT, 1, stats);
293                 stats->totobj++;
294         }
295         else if (ob->parent && (ob->parent->transflag & (OB_DUPLIVERTS | OB_DUPLIFACES))) {
296                 /* Dupli Verts/Faces */
297                 int tot = count_duplilist(ob->parent);
298                 stats->totobj += tot;
299                 stats_object(ob, base->flag & SELECT, tot, stats);
300         }
301         else if (ob->transflag & OB_DUPLIFRAMES) {
302                 /* Dupli Frames */
303                 int tot = count_duplilist(ob);
304                 stats->totobj += tot;
305                 stats_object(ob, base->flag & SELECT, tot, stats);
306         }
307         else if ((ob->transflag & OB_DUPLIGROUP) && ob->dup_group) {
308                 /* Dupli Group */
309                 int tot = count_duplilist(ob);
310                 stats->totobj += tot;
311                 stats_object(ob, base->flag & SELECT, tot, stats);
312         }
313         else {
314                 /* No Dupli */
315                 stats_object(ob, base->flag & SELECT, 1, stats);
316                 stats->totobj++;
317         }
318 }
319
320 static int stats_is_object_dynamic_topology_sculpt(Object *ob)
321 {
322         return (ob && (ob->mode & OB_MODE_SCULPT) &&
323                 ob->sculpt && ob->sculpt->bm);
324 }
325
326 /* Statistics displayed in info header. Called regularly on scene changes. */
327 static void stats_update(Scene *scene)
328 {
329         SceneStats stats = {0};
330         Object *ob = (scene->basact) ? scene->basact->object : NULL;
331         Base *base;
332         
333         if (scene->obedit) {
334                 /* Edit Mode */
335                 stats_object_edit(scene->obedit, &stats);
336         }
337         else if (ob && (ob->mode & OB_MODE_POSE)) {
338                 /* Pose Mode */
339                 stats_object_pose(ob, &stats);
340         }
341         else if (stats_is_object_dynamic_topology_sculpt(ob)) {
342                 /* Dynamic-topology sculpt mode */
343                 stats_object_sculpt_dynamic_topology(ob, &stats);
344         }
345         else {
346                 /* Objects */
347                 for (base = scene->base.first; base; base = base->next)
348                         if (scene->lay & base->lay)
349                                 stats_dupli_object(base, base->object, &stats);
350         }
351
352         if (!scene->stats)
353                 scene->stats = MEM_callocN(sizeof(SceneStats), "SceneStats");
354
355         *(scene->stats) = stats;
356 }
357
358 static void stats_string(Scene *scene)
359 {
360         SceneStats *stats = scene->stats;
361         Object *ob = (scene->basact) ? scene->basact->object : NULL;
362         uintptr_t mem_in_use, mmap_in_use;
363         char memstr[64];
364         char *s;
365
366         mem_in_use = MEM_get_memory_in_use();
367         mmap_in_use = MEM_get_mapped_memory_in_use();
368
369         /* get memory statistics */
370         s = memstr + sprintf(memstr, IFACE_(" | Mem:%.2fM"), (double)((mem_in_use - mmap_in_use) >> 10) / 1024.0);
371         if (mmap_in_use)
372                 sprintf(s, IFACE_(" (%.2fM)"), (double)((mmap_in_use) >> 10) / 1024.0);
373
374         s = stats->infostr;
375         
376         s += sprintf(s, "%s | ", versionstr);
377
378         if (scene->obedit) {
379                 if (BKE_keyblock_from_object(scene->obedit))
380                         s += sprintf(s, IFACE_("(Key) "));
381
382                 if (scene->obedit->type == OB_MESH) {
383                         s += sprintf(s, IFACE_("Verts:%d/%d | Edges:%d/%d | Faces:%d/%d | Tris:%d"),
384                                  stats->totvertsel, stats->totvert, stats->totedgesel, stats->totedge, stats->totfacesel,
385                                  stats->totface, stats->tottri);
386                 }
387                 else if (scene->obedit->type == OB_ARMATURE) {
388                         s += sprintf(s, IFACE_("Verts:%d/%d | Bones:%d/%d"), stats->totvertsel, stats->totvert, stats->totbonesel,
389                                      stats->totbone);
390                 }
391                 else {
392                         s += sprintf(s, IFACE_("Verts:%d/%d"), stats->totvertsel, stats->totvert);
393                 }
394
395                 strcat(s, memstr);
396         }
397         else if (ob && (ob->mode & OB_MODE_POSE)) {
398                 s += sprintf(s, IFACE_("Bones:%d/%d %s"),
399                              stats->totbonesel, stats->totbone, memstr);
400         }
401         else if (stats_is_object_dynamic_topology_sculpt(ob)) {
402                 s += sprintf(s, IFACE_("Verts:%d | Tris:%d"), stats->totvert, stats->tottri);
403         }
404         else {
405                 s += sprintf(s, IFACE_("Verts:%d | Faces:%d | Tris:%d | Objects:%d/%d | Lamps:%d/%d%s"),
406                              stats->totvert, stats->totface, stats->tottri, stats->totobjsel, stats->totobj, stats->totlampsel,
407                              stats->totlamp, memstr);
408         }
409
410         if (ob)
411                 sprintf(s, " | %s", ob->id.name + 2);
412 }
413
414 void ED_info_stats_clear(Scene *scene)
415 {
416         if (scene->stats) {
417                 MEM_freeN(scene->stats);
418                 scene->stats = NULL;
419         }
420 }
421
422 const char *ED_info_stats_string(Scene *scene)
423 {
424         if (!scene->stats)
425                 stats_update(scene);
426         stats_string(scene);
427
428         return scene->stats->infostr;
429 }