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