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