2.5: Restored statistics in the info header.
[blender.git] / source / blender / editors / space_info / info_stats.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * Contributor(s): Blender Foundation
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 #include <stdio.h>
26 #include <string.h>
27
28 #include "MEM_guardedalloc.h"
29
30 #include "DNA_action_types.h"
31 #include "DNA_armature_types.h"
32 #include "DNA_curve_types.h"
33 #include "DNA_group_types.h"
34 #include "DNA_lattice_types.h"
35 #include "DNA_mesh_types.h"
36 #include "DNA_meta_types.h"
37 #include "DNA_object_types.h"
38 #include "DNA_particle_types.h"
39 #include "DNA_scene_types.h"
40
41 #include "BKE_anim.h"
42 #include "BKE_context.h"
43 #include "BKE_displist.h"
44 #include "BKE_DerivedMesh.h"
45 #include "BKE_key.h"
46 #include "BKE_mesh.h"
47 #include "BKE_particle.h"
48 #include "BKE_utildefines.h"
49
50 #include "ED_armature.h"
51 #include "ED_mesh.h"
52
53 #include "BLI_editVert.h"
54
55 typedef struct SceneStats {
56         int totvert, totvertsel;
57         int totedge, totedgesel;
58         int totface, totfacesel;
59         int totbone, totbonesel;
60         int totobj, totobjsel;
61         int totmesh, totlamp, totcurve;
62
63         char infostr[512];
64 } SceneStats;
65
66 static void stats_object(Object *ob, int sel, int totob, SceneStats *stats)
67 {
68         switch(ob->type) {
69         case OB_MESH: {
70                 /* we assume derivedmesh is already built, this strictly does stats now. */
71                 DerivedMesh *dm= ob->derivedFinal;
72                 int totvert, totedge, totface;
73
74                 stats->totmesh +=totob;
75
76                 if(dm) {
77                         totvert = dm->getNumVerts(dm);
78                         totedge = dm->getNumEdges(dm);
79                         totface = dm->getNumFaces(dm);
80
81                         stats->totvert += totvert*totob;
82                         stats->totedge += totedge*totob;
83                         stats->totface += totface*totob;
84
85                         if(sel) {
86                                 stats->totvertsel += totvert;
87                                 stats->totfacesel += totface;
88                         }
89                 }
90                 break;
91         }
92         case OB_LAMP:
93                 stats->totlamp += totob;
94                 break;
95         case OB_SURF:
96         case OB_CURVE:
97         case OB_FONT: {
98                 Curve *cu= ob->data;
99                 int tot= 0, totf= 0;
100
101                 stats->totcurve += totob;
102
103                 if(cu->disp.first)
104                         count_displist(&cu->disp, &tot, &totf);
105
106                 tot *= totob;
107                 totf *= totob;
108
109                 stats->totvert+= tot;
110                 stats->totface+= totf;
111
112                 if(sel) {
113                         stats->totvertsel += tot;
114                         stats->totfacesel += totf;
115                 }
116                 break;
117         }
118         case OB_MBALL: {
119                 int tot= 0, totf= 0;
120
121                 count_displist(&ob->disp, &tot, &totf);
122
123                 tot *= totob;
124                 totf *= totob;
125
126                 stats->totvert += tot;
127                 stats->totface += totf;
128
129                 if(sel) {
130                         stats->totvertsel += tot;
131                         stats->totfacesel += totf;
132                 }
133                 break;
134         }
135         }
136 }
137
138 static void stats_object_edit(Object *obedit, SceneStats *stats)
139 {
140         if(obedit->type==OB_MESH) {
141                 /* Mesh Edit */
142                 EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
143                 EditVert *eve;
144                 EditEdge *eed;
145                 EditFace *efa;
146                 
147                 for(eve= em->verts.first; eve; eve=eve->next) {
148                         stats->totvert++;
149                         if(eve->f & SELECT) stats->totvertsel++;
150                 }
151                 for(eed= em->edges.first; eed; eed=eed->next) {
152                         stats->totedge++;
153                         if(eed->f & SELECT) stats->totedgesel++;
154                 }
155                 for(efa= em->faces.first; efa; efa=efa->next) {
156                         stats->totface++;
157                         if(efa->f & SELECT) stats->totfacesel++;
158                 }
159                 
160                 EM_validate_selections(em);
161         }
162         else if(obedit->type==OB_ARMATURE){
163                 /* Armature Edit */
164                 bArmature *arm= obedit->data;
165                 EditBone *ebo;
166
167                 for(ebo=arm->edbo->first; ebo; ebo=ebo->next){
168                         stats->totbone++;
169                         
170                         if((ebo->flag & BONE_CONNECTED) && ebo->parent)
171                                 stats->totvert--;
172                         
173                         if(ebo->flag & BONE_TIPSEL)
174                                 stats->totvertsel++;
175                         if(ebo->flag & BONE_ROOTSEL)
176                                 stats->totvertsel++;
177                         
178                         if(ebo->flag & BONE_SELECTED) stats->totbonesel++;
179
180                         /* if this is a connected child and it's parent is being moved, remove our root */
181                         if((ebo->flag & BONE_CONNECTED)&& (ebo->flag & BONE_ROOTSEL) && ebo->parent && (ebo->parent->flag & BONE_TIPSEL))
182                                 stats->totvertsel--;
183
184                         stats->totvert+=2;
185                 }
186         }
187         else if ELEM3(obedit->type, OB_CURVE, OB_SURF, OB_FONT) {
188                 /* Curve Edit */
189                 Curve *cu= obedit->data;
190                 Nurb *nu;
191                 BezTriple *bezt;
192                 BPoint *bp;
193                 int a;
194
195                 for(nu=cu->editnurb->first; nu; nu=nu->next) {
196                         if((nu->type & 7)==CU_BEZIER) {
197                                 bezt= nu->bezt;
198                                 a= nu->pntsu;
199                                 while(a--) {
200                                         stats->totvert+=3;
201                                         if(bezt->f1) stats->totvertsel++;
202                                         if(bezt->f2) stats->totvertsel++;
203                                         if(bezt->f3) stats->totvertsel++;
204                                         bezt++;
205                                 }
206                         }
207                         else {
208                                 bp= nu->bp;
209                                 a= nu->pntsu*nu->pntsv;
210                                 while(a--) {
211                                         stats->totvert++;
212                                         if(bp->f1 & SELECT) stats->totvertsel++;
213                                         bp++;
214                                 }
215                         }
216                 }
217         }
218         else if(obedit->type==OB_MBALL) {
219                 /* MetaBall Edit */
220                 MetaBall *mball= obedit->data;
221                 MetaElem *ml;
222                 
223                 for(ml= mball->editelems->first; ml; ml=ml->next) {
224                         stats->totvert++;
225                         if(ml->flag & SELECT) stats->totvertsel++;
226                 }
227         }
228         else if(obedit->type==OB_LATTICE) {
229                 /* Lattice Edit */
230                 Lattice *lt= obedit->data;
231                 Lattice *editlatt= lt->editlatt;
232                 BPoint *bp;
233                 int a;
234
235                 bp= editlatt->def;
236                 
237                 a= editlatt->pntsu*editlatt->pntsv*editlatt->pntsw;
238                 while(a--) {
239                         stats->totvert++;
240                         if(bp->f1 & SELECT) stats->totvertsel++;
241                         bp++;
242                 }
243         }
244 }
245
246 static void stats_object_pose(Object *ob, SceneStats *stats)
247 {
248         if(ob->pose) {
249                 bArmature *arm= ob->data;
250                 bPoseChannel *pchan;
251
252                 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
253                         stats->totbone++;
254                         if(pchan->bone && (pchan->bone->flag & BONE_SELECTED))
255                                 if(pchan->bone->layer & arm->layer)
256                                         stats->totbonesel++;
257                 }
258         }
259 }
260
261 static void stats_object_paint(Object *ob, SceneStats *stats)
262 {
263         if(ob->type == OB_MESH) {
264                 Mesh *me= ob->data;
265
266                 stats->totface= me->totface;
267                 stats->totvert= me->totvert;
268         }
269 }
270
271 static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats)
272 {
273         if(base->flag & SELECT) stats->totobjsel++;
274
275         if(ob->transflag & OB_DUPLIPARTS) {
276                 /* Dupli Particles */
277                 ParticleSystem *psys;
278                 ParticleSettings *part;
279
280                 for(psys=ob->particlesystem.first; psys; psys=psys->next){
281                         part=psys->part;
282
283                         if(part->draw_as==PART_DRAW_OB && part->dup_ob){
284                                 int tot=count_particles(psys);
285                                 stats_object(part->dup_ob, 0, tot, stats);
286                         }
287                         else if(part->draw_as==PART_DRAW_GR && part->dup_group){
288                                 GroupObject *go;
289                                 int tot, totgroup=0, cur=0;
290                                 
291                                 for(go= part->dup_group->gobject.first; go; go=go->next)
292                                         totgroup++;
293
294                                 for(go= part->dup_group->gobject.first; go; go=go->next) {
295                                         tot=count_particles_mod(psys,totgroup,cur);
296                                         stats_object(go->ob, 0, tot, stats);
297                                         cur++;
298                                 }
299                         }
300                 }
301                 
302                 stats_object(ob, base->flag & SELECT, 1, stats);
303                 stats->totobj++;
304         }
305         else if(ob->parent && (ob->parent->transflag & (OB_DUPLIVERTS|OB_DUPLIFACES))) {
306                 /* Dupli Verts/Faces */
307                 int tot= count_duplilist(ob->parent);
308                 stats->totobj+=tot;
309                 stats_object(ob, base->flag & SELECT, tot, stats);
310         }
311         else if(ob->transflag & OB_DUPLIFRAMES) {
312                 /* Dupli Frames */
313                 int tot= count_duplilist(ob);
314                 stats->totobj+=tot;
315                 stats_object(ob, base->flag & SELECT, tot, stats);
316         }
317         else if((ob->transflag & OB_DUPLIGROUP) && ob->dup_group) {
318                 /* Dupli Group */
319                 int tot= count_duplilist(ob);
320                 stats->totobj+=tot;
321                 stats_object(ob, base->flag & SELECT, tot, stats);
322         }
323         else {
324                 /* No Dupli */
325                 stats_object(ob, base->flag & SELECT, 1, stats);
326                 stats->totobj++;
327         }
328 }
329
330 /* Statistics displayed in info header. Called regularly on scene changes. */
331 static void stats_update(Scene *scene)
332 {
333         SceneStats stats;
334         Object *ob= (scene->basact)? scene->basact->object: NULL;
335         Base *base;
336         
337         memset(&stats, 0, sizeof(stats));
338
339         if(scene->obedit) {
340                 /* Edit Mode */
341                 stats_object_edit(scene->obedit, &stats);
342         }
343         else if(ob && (ob->mode & OB_MODE_POSE)) {
344                 /* Pose Mode */
345                 stats_object_pose(ob, &stats);
346         }
347         else if(ob && (ob->flag & (OB_MODE_SCULPT|OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT))) {
348                 /* Sculpt and Paint Mode */
349                 stats_object_paint(ob, &stats);
350         }
351         else {
352                 /* Objects */
353                 for(base= scene->base.first; base; base=base->next)
354                         if(scene->lay & base->lay)
355                                 stats_dupli_object(base, base->object, &stats);
356         }
357
358         if(!scene->stats)
359                 scene->stats= MEM_mallocN(sizeof(SceneStats), "SceneStats");
360
361         *(scene->stats)= stats;
362 }
363
364 static void stats_string(Scene *scene)
365 {
366         SceneStats *stats= scene->stats;
367         Object *ob= (scene->basact)? scene->basact->object: NULL;
368         uintptr_t mem_in_use, mmap_in_use;
369         char memstr[64];
370         char *s;
371
372         mem_in_use= MEM_get_memory_in_use();
373         mmap_in_use= MEM_get_mapped_memory_in_use();
374
375         /* get memory statistics */
376         s= memstr + sprintf(memstr, " | Mem:%.2fM", ((mem_in_use-mmap_in_use)>>10)/1024.0);
377         if(mmap_in_use)
378                 sprintf(s, " (%.2fM)", ((mmap_in_use)>>10)/1024.0);
379
380         s= stats->infostr;
381
382         if(scene->obedit) {
383                 if(ob_get_keyblock(scene->obedit))
384                         s+= sprintf(s, "(Key) ");
385
386                 if(scene->obedit->type==OB_MESH) {
387                         if(scene->toolsettings->selectmode & SCE_SELECT_VERTEX)
388                                 s+= sprintf(s, "Ve:%d-%d | Ed:%d-%d | Fa:%d-%d",
389                                                 stats->totvertsel, stats->totvert, stats->totedgesel, stats->totedge, stats->totfacesel, stats->totface);
390                         else if(scene->toolsettings->selectmode & SCE_SELECT_EDGE)
391                                 s+= sprintf(s, "Ed:%d-%d | Fa:%d-%d",
392                                                 stats->totedgesel, stats->totedge, stats->totfacesel, stats->totface);
393                         else
394                                 s+= sprintf(s, "Fa:%d-%d", stats->totfacesel, stats->totface);
395                 }
396                 else if(scene->obedit->type==OB_ARMATURE) {
397                         s+= sprintf(s, "Ve:%d-%d | Bo:%d-%d", stats->totvertsel, stats->totvert, stats->totbonesel, stats->totbone);
398                 }
399                 else {
400                         s+= sprintf(s, "Ve:%d-%d", stats->totvertsel, stats->totvert);
401                 }
402
403                 strcat(s, memstr);
404         }
405         else if(ob && (ob->mode & OB_MODE_POSE)) {
406                 s += sprintf(s, "Bo:%d-%d %s",
407                                         stats->totbonesel, stats->totbone, memstr);
408         }
409         else {
410                 s += sprintf(s, "Ve:%d | Fa:%d | Ob:%d-%d | La:%d%s",
411                         stats->totvert, stats->totface, stats->totobj, stats->totobjsel, stats->totlamp, memstr);
412         }
413
414         if(ob)
415                 sprintf(s, " | %s", ob->id.name+2);
416 }
417
418 void ED_info_stats_clear(Scene *scene)
419 {
420         if(scene->stats) {
421                 MEM_freeN(scene->stats);
422                 scene->stats= NULL;
423         }
424 }
425
426 char *ED_info_stats_string(Scene *scene)
427 {
428         if(!scene->stats)
429                 stats_update(scene);
430         stats_string(scene);
431
432         return scene->stats->infostr;
433 }
434