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