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