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