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