Code cleanup: use bool for static methods
[blender.git] / source / blender / editors / space_info / info_stats.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Blender Foundation
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/editors/space_info/info_stats.c
24  *  \ingroup spinfo
25  */
26
27
28 #include <stdio.h>
29 #include <string.h>
30
31 #include "MEM_guardedalloc.h"
32
33 #include "DNA_armature_types.h"
34 #include "DNA_curve_types.h"
35 #include "DNA_group_types.h"
36 #include "DNA_lattice_types.h"
37 #include "DNA_mesh_types.h"
38 #include "DNA_meta_types.h"
39 #include "DNA_scene_types.h"
40
41 #include "BLI_math.h"
42 #include "BLI_string.h"
43 #include "BLI_utildefines.h"
44
45 #include "BLF_translation.h"
46
47 #include "BKE_anim.h"
48 #include "BKE_blender.h"
49 #include "BKE_curve.h"
50 #include "BKE_displist.h"
51 #include "BKE_DerivedMesh.h"
52 #include "BKE_key.h"
53 #include "BKE_mesh.h"
54 #include "BKE_paint.h"
55 #include "BKE_particle.h"
56 #include "BKE_editmesh.h"
57
58 #include "ED_info.h"
59 #include "ED_armature.h"
60 #include "ED_mesh.h"
61
62 #define MAX_INFO_LEN 512
63
64 typedef struct SceneStats {
65         int totvert, totvertsel;
66         int totedge, totedgesel;
67         int totface, totfacesel;
68         int totbone, totbonesel;
69         int totobj,  totobjsel;
70         int totlamp, totlampsel; 
71         int tottri, totmesh;
72
73         char infostr[MAX_INFO_LEN];
74 } SceneStats;
75
76 static void stats_object(Object *ob, int sel, int totob, SceneStats *stats)
77 {
78         switch (ob->type) {
79                 case OB_MESH:
80                 {
81                         /* we assume derivedmesh is already built, this strictly does stats now. */
82                         DerivedMesh *dm = ob->derivedFinal;
83                         int totvert, totedge, totface, totloop;
84
85                         stats->totmesh += totob;
86
87                         if (dm) {
88                                 totvert = dm->getNumVerts(dm);
89                                 totedge = dm->getNumEdges(dm);
90                                 totface = dm->getNumPolys(dm);
91                                 totloop = dm->getNumLoops(dm);
92
93                                 stats->totvert += totvert * totob;
94                                 stats->totedge += totedge * totob;
95                                 stats->totface += totface * totob;
96                                 stats->tottri  += poly_to_tri_count(totface, totloop) * totob;
97
98                                 if (sel) {
99                                         stats->totvertsel += totvert;
100                                         stats->totfacesel += totface;
101                                 }
102                         }
103                         break;
104                 }
105                 case OB_LAMP:
106                         stats->totlamp += totob;
107                         if (sel) {
108                                 stats->totlampsel += totob;
109                         }
110                         break;
111                 case OB_SURF:
112                 case OB_CURVE:
113                 case OB_FONT:
114                 case OB_MBALL:
115                 {
116                         int totv = 0, totf = 0, tottri = 0;
117
118                         if (ob->curve_cache && ob->curve_cache->disp.first)
119                                 BKE_displist_count(&ob->curve_cache->disp, &totv, &totf, &tottri);
120
121                         totv   *= totob;
122                         totf   *= totob;
123                         tottri *= totob;
124
125                         stats->totvert += totv;
126                         stats->totface += totf;
127                         stats->tottri  += tottri;
128
129                         if (sel) {
130                                 stats->totvertsel += totv;
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                 BMEditMesh *em = BKE_editmesh_from_object(obedit);
142
143                 stats->totvert = em->bm->totvert;
144                 stats->totvertsel = em->bm->totvertsel;
145                 
146                 stats->totedge = em->bm->totedge;
147                 stats->totedgesel = em->bm->totedgesel;
148                 
149                 stats->totface = em->bm->totface;
150                 stats->totfacesel = em->bm->totfacesel;
151
152                 stats->tottri = em->tottri;
153         }
154         else if (obedit->type == OB_ARMATURE) {
155                 /* Armature Edit */
156                 bArmature *arm = obedit->data;
157                 EditBone *ebo;
158
159                 for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
160                         stats->totbone++;
161                         
162                         if ((ebo->flag & BONE_CONNECTED) && ebo->parent)
163                                 stats->totvert--;
164                         
165                         if (ebo->flag & BONE_TIPSEL)
166                                 stats->totvertsel++;
167                         if (ebo->flag & BONE_ROOTSEL)
168                                 stats->totvertsel++;
169                         
170                         if (ebo->flag & BONE_SELECTED) stats->totbonesel++;
171
172                         /* if this is a connected child and it's parent is being moved, remove our root */
173                         if ((ebo->flag & BONE_CONNECTED) && (ebo->flag & BONE_ROOTSEL) &&
174                             ebo->parent && (ebo->parent->flag & BONE_TIPSEL))
175                         {
176                                 stats->totvertsel--;
177                         }
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 = BKE_curve_editNurbs_get(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 & SELECT) stats->totvertsel++;
198                                         if (bezt->f2 & SELECT) stats->totvertsel++;
199                                         if (bezt->f3 & SELECT) 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_sculpt_dynamic_topology(Object *ob, SceneStats *stats)
258 {
259         stats->totvert = ob->sculpt->bm->totvert;
260         stats->tottri = ob->sculpt->bm->totface;
261 }
262
263 static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats)
264 {
265         if (base->flag & SELECT) stats->totobjsel++;
266
267         if (ob->transflag & OB_DUPLIPARTS) {
268                 /* Dupli Particles */
269                 ParticleSystem *psys;
270                 ParticleSettings *part;
271
272                 for (psys = ob->particlesystem.first; psys; psys = psys->next) {
273                         part = psys->part;
274
275                         if (part->draw_as == PART_DRAW_OB && part->dup_ob) {
276                                 int tot = count_particles(psys);
277                                 stats_object(part->dup_ob, 0, tot, stats);
278                         }
279                         else if (part->draw_as == PART_DRAW_GR && part->dup_group) {
280                                 GroupObject *go;
281                                 int tot, totgroup = 0, cur = 0;
282                                 
283                                 for (go = part->dup_group->gobject.first; go; go = go->next)
284                                         totgroup++;
285
286                                 for (go = part->dup_group->gobject.first; go; go = go->next) {
287                                         tot = count_particles_mod(psys, totgroup, cur);
288                                         stats_object(go->ob, 0, tot, stats);
289                                         cur++;
290                                 }
291                         }
292                 }
293                 
294                 stats_object(ob, base->flag & SELECT, 1, stats);
295                 stats->totobj++;
296         }
297         else if (ob->parent && (ob->parent->transflag & (OB_DUPLIVERTS | OB_DUPLIFACES))) {
298                 /* Dupli Verts/Faces */
299                 int tot;
300
301                 /* metaball dupli-instances are tessellated once */
302                 if (ob->type == OB_MBALL) {
303                         tot = 1;
304                 }
305                 else {
306                         tot = count_duplilist(ob->parent);
307                 }
308
309                 stats->totobj += tot;
310                 stats_object(ob, base->flag & SELECT, tot, stats);
311         }
312         else if (ob->transflag & OB_DUPLIFRAMES) {
313                 /* Dupli Frames */
314                 int tot = count_duplilist(ob);
315                 stats->totobj += tot;
316                 stats_object(ob, base->flag & SELECT, tot, stats);
317         }
318         else if ((ob->transflag & OB_DUPLIGROUP) && ob->dup_group) {
319                 /* Dupli Group */
320                 int tot = count_duplilist(ob);
321                 stats->totobj += tot;
322                 stats_object(ob, base->flag & SELECT, tot, stats);
323         }
324         else {
325                 /* No Dupli */
326                 stats_object(ob, base->flag & SELECT, 1, stats);
327                 stats->totobj++;
328         }
329 }
330
331 static bool stats_is_object_dynamic_topology_sculpt(Object *ob)
332 {
333         return (ob && (ob->mode & OB_MODE_SCULPT) &&
334                 ob->sculpt && ob->sculpt->bm);
335 }
336
337 /* Statistics displayed in info header. Called regularly on scene changes. */
338 static void stats_update(Scene *scene)
339 {
340         SceneStats stats = {0};
341         Object *ob = (scene->basact) ? scene->basact->object : NULL;
342         Base *base;
343         
344         if (scene->obedit) {
345                 /* Edit Mode */
346                 stats_object_edit(scene->obedit, &stats);
347         }
348         else if (ob && (ob->mode & OB_MODE_POSE)) {
349                 /* Pose Mode */
350                 stats_object_pose(ob, &stats);
351         }
352         else if (stats_is_object_dynamic_topology_sculpt(ob)) {
353                 /* Dynamic-topology sculpt mode */
354                 stats_object_sculpt_dynamic_topology(ob, &stats);
355         }
356         else {
357                 /* Objects */
358                 for (base = scene->base.first; base; base = base->next)
359                         if (scene->lay & base->lay)
360                                 stats_dupli_object(base, base->object, &stats);
361         }
362
363         if (!scene->stats)
364                 scene->stats = MEM_callocN(sizeof(SceneStats), "SceneStats");
365
366         *(scene->stats) = stats;
367 }
368
369 static void stats_string(Scene *scene)
370 {
371 #define MAX_INFO_MEM_LEN  64
372         SceneStats *stats = scene->stats;
373         Object *ob = (scene->basact) ? scene->basact->object : NULL;
374         uintptr_t mem_in_use, mmap_in_use;
375         char memstr[MAX_INFO_MEM_LEN];
376         char *s;
377         size_t ofs = 0;
378
379         mem_in_use = MEM_get_memory_in_use();
380         mmap_in_use = MEM_get_mapped_memory_in_use();
381
382         /* get memory statistics */
383         s = memstr;
384         ofs += BLI_snprintf(s + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_(" | Mem:%.2fM"),
385                             (double)((mem_in_use - mmap_in_use) >> 10) / 1024.0);
386         if (mmap_in_use)
387                 BLI_snprintf(s + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_(" (%.2fM)"), (double)((mmap_in_use) >> 10) / 1024.0);
388
389         s = stats->infostr;
390         ofs = 0;
391
392         ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, "%s | ", versionstr);
393
394         if (scene->obedit) {
395                 if (BKE_keyblock_from_object(scene->obedit))
396                         ofs += BLI_strncpy_rlen(s + ofs, IFACE_("(Key) "), MAX_INFO_LEN - ofs);
397
398                 if (scene->obedit->type == OB_MESH) {
399                         ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs,
400                                             IFACE_("Verts:%d/%d | Edges:%d/%d | Faces:%d/%d | Tris:%d"),
401                                         stats->totvertsel, stats->totvert, stats->totedgesel, stats->totedge,
402                                         stats->totfacesel, stats->totface, stats->tottri);
403                 }
404                 else if (scene->obedit->type == OB_ARMATURE) {
405                         ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%d/%d | Bones:%d/%d"), stats->totvertsel,
406                                             stats->totvert, stats->totbonesel, stats->totbone);
407                 }
408                 else {
409                         ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%d/%d"), stats->totvertsel, stats->totvert);
410                 }
411
412                 ofs += BLI_strncpy_rlen(s + ofs, memstr, MAX_INFO_LEN - ofs);
413         }
414         else if (ob && (ob->mode & OB_MODE_POSE)) {
415                 ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Bones:%d/%d %s"),
416                                     stats->totbonesel, stats->totbone, memstr);
417         }
418         else if (stats_is_object_dynamic_topology_sculpt(ob)) {
419                 ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%d | Tris:%d"), stats->totvert, stats->tottri);
420         }
421         else {
422                 ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs,
423                                     IFACE_("Verts:%d | Faces:%d | Tris:%d | Objects:%d/%d | Lamps:%d/%d%s"), stats->totvert,
424                                     stats->totface, stats->tottri, stats->totobjsel, stats->totobj, stats->totlampsel,
425                                     stats->totlamp, memstr);
426         }
427
428         if (ob)
429                 BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, " | %s", ob->id.name + 2);
430 #undef MAX_INFO_MEM_LEN
431 }
432
433 #undef MAX_INFO_LEN
434
435 void ED_info_stats_clear(Scene *scene)
436 {
437         if (scene->stats) {
438                 MEM_freeN(scene->stats);
439                 scene->stats = NULL;
440         }
441 }
442
443 const char *ED_info_stats_string(Scene *scene)
444 {
445         if (!scene->stats)
446                 stats_update(scene);
447         stats_string(scene);
448
449         return scene->stats->infostr;
450 }