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