/** * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Contributor(s): Blender Foundation * * ***** END GPL LICENSE BLOCK ***** */ #include #include #include "MEM_guardedalloc.h" #include "DNA_armature_types.h" #include "DNA_curve_types.h" #include "DNA_group_types.h" #include "DNA_lattice_types.h" #include "DNA_meta_types.h" #include "DNA_scene_types.h" #include "BKE_anim.h" #include "BKE_displist.h" #include "BKE_DerivedMesh.h" #include "BKE_key.h" #include "BKE_mesh.h" #include "BKE_particle.h" #include "BKE_utildefines.h" #include "ED_armature.h" #include "ED_mesh.h" #include "ED_curve.h" /* for ED_curve_editnurbs */ #include "BLI_editVert.h" typedef struct SceneStats { int totvert, totvertsel; int totedge, totedgesel; int totface, totfacesel; int totbone, totbonesel; int totobj, totobjsel; int totmesh, totlamp, totcurve; char infostr[512]; } SceneStats; static void stats_object(Object *ob, int sel, int totob, SceneStats *stats) { switch(ob->type) { case OB_MESH: { /* we assume derivedmesh is already built, this strictly does stats now. */ DerivedMesh *dm= ob->derivedFinal; int totvert, totedge, totface; stats->totmesh +=totob; if(dm) { totvert = dm->getNumVerts(dm); totedge = dm->getNumEdges(dm); totface = dm->getNumFaces(dm); stats->totvert += totvert*totob; stats->totedge += totedge*totob; stats->totface += totface*totob; if(sel) { stats->totvertsel += totvert; stats->totfacesel += totface; } } break; } case OB_LAMP: stats->totlamp += totob; break; case OB_SURF: case OB_CURVE: case OB_FONT: { Curve *cu= ob->data; int tot= 0, totf= 0; stats->totcurve += totob; if(cu->disp.first) count_displist(&cu->disp, &tot, &totf); tot *= totob; totf *= totob; stats->totvert+= tot; stats->totface+= totf; if(sel) { stats->totvertsel += tot; stats->totfacesel += totf; } break; } case OB_MBALL: { int tot= 0, totf= 0; count_displist(&ob->disp, &tot, &totf); tot *= totob; totf *= totob; stats->totvert += tot; stats->totface += totf; if(sel) { stats->totvertsel += tot; stats->totfacesel += totf; } break; } } } static void stats_object_edit(Object *obedit, SceneStats *stats) { if(obedit->type==OB_MESH) { /* Mesh Edit */ EditMesh *em= BKE_mesh_get_editmesh(obedit->data); EditVert *eve; EditEdge *eed; EditFace *efa; for(eve= em->verts.first; eve; eve=eve->next) { stats->totvert++; if(eve->f & SELECT) stats->totvertsel++; } for(eed= em->edges.first; eed; eed=eed->next) { stats->totedge++; if(eed->f & SELECT) stats->totedgesel++; } for(efa= em->faces.first; efa; efa=efa->next) { stats->totface++; if(efa->f & SELECT) stats->totfacesel++; } EM_validate_selections(em); } else if(obedit->type==OB_ARMATURE){ /* Armature Edit */ bArmature *arm= obedit->data; EditBone *ebo; for(ebo=arm->edbo->first; ebo; ebo=ebo->next){ stats->totbone++; if((ebo->flag & BONE_CONNECTED) && ebo->parent) stats->totvert--; if(ebo->flag & BONE_TIPSEL) stats->totvertsel++; if(ebo->flag & BONE_ROOTSEL) stats->totvertsel++; if(ebo->flag & BONE_SELECTED) stats->totbonesel++; /* if this is a connected child and it's parent is being moved, remove our root */ if((ebo->flag & BONE_CONNECTED)&& (ebo->flag & BONE_ROOTSEL) && ebo->parent && (ebo->parent->flag & BONE_TIPSEL)) stats->totvertsel--; stats->totvert+=2; } } else if ELEM(obedit->type, OB_CURVE, OB_SURF) { /* OB_FONT has no cu->editnurb */ /* Curve Edit */ Curve *cu= obedit->data; Nurb *nu; BezTriple *bezt; BPoint *bp; int a; ListBase *nurbs= ED_curve_editnurbs(cu); for(nu=nurbs->first; nu; nu=nu->next) { if(nu->type == CU_BEZIER) { bezt= nu->bezt; a= nu->pntsu; while(a--) { stats->totvert+=3; if(bezt->f1) stats->totvertsel++; if(bezt->f2) stats->totvertsel++; if(bezt->f3) stats->totvertsel++; bezt++; } } else { bp= nu->bp; a= nu->pntsu*nu->pntsv; while(a--) { stats->totvert++; if(bp->f1 & SELECT) stats->totvertsel++; bp++; } } } } else if(obedit->type==OB_MBALL) { /* MetaBall Edit */ MetaBall *mball= obedit->data; MetaElem *ml; for(ml= mball->editelems->first; ml; ml=ml->next) { stats->totvert++; if(ml->flag & SELECT) stats->totvertsel++; } } else if(obedit->type==OB_LATTICE) { /* Lattice Edit */ Lattice *lt= obedit->data; Lattice *editlatt= lt->editlatt->latt; BPoint *bp; int a; bp= editlatt->def; a= editlatt->pntsu*editlatt->pntsv*editlatt->pntsw; while(a--) { stats->totvert++; if(bp->f1 & SELECT) stats->totvertsel++; bp++; } } } static void stats_object_pose(Object *ob, SceneStats *stats) { if(ob->pose) { bArmature *arm= ob->data; bPoseChannel *pchan; for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { stats->totbone++; if(pchan->bone && (pchan->bone->flag & BONE_SELECTED)) if(pchan->bone->layer & arm->layer) stats->totbonesel++; } } } static void stats_object_paint(Object *ob, SceneStats *stats) { if(ob->type == OB_MESH) { Mesh *me= ob->data; stats->totface= me->totface; stats->totvert= me->totvert; } } static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats) { if(base->flag & SELECT) stats->totobjsel++; if(ob->transflag & OB_DUPLIPARTS) { /* Dupli Particles */ ParticleSystem *psys; ParticleSettings *part; for(psys=ob->particlesystem.first; psys; psys=psys->next){ part=psys->part; if(part->draw_as==PART_DRAW_OB && part->dup_ob){ int tot=count_particles(psys); stats_object(part->dup_ob, 0, tot, stats); } else if(part->draw_as==PART_DRAW_GR && part->dup_group){ GroupObject *go; int tot, totgroup=0, cur=0; for(go= part->dup_group->gobject.first; go; go=go->next) totgroup++; for(go= part->dup_group->gobject.first; go; go=go->next) { tot=count_particles_mod(psys,totgroup,cur); stats_object(go->ob, 0, tot, stats); cur++; } } } stats_object(ob, base->flag & SELECT, 1, stats); stats->totobj++; } else if(ob->parent && (ob->parent->transflag & (OB_DUPLIVERTS|OB_DUPLIFACES))) { /* Dupli Verts/Faces */ int tot= count_duplilist(ob->parent); stats->totobj+=tot; stats_object(ob, base->flag & SELECT, tot, stats); } else if(ob->transflag & OB_DUPLIFRAMES) { /* Dupli Frames */ int tot= count_duplilist(ob); stats->totobj+=tot; stats_object(ob, base->flag & SELECT, tot, stats); } else if((ob->transflag & OB_DUPLIGROUP) && ob->dup_group) { /* Dupli Group */ int tot= count_duplilist(ob); stats->totobj+=tot; stats_object(ob, base->flag & SELECT, tot, stats); } else { /* No Dupli */ stats_object(ob, base->flag & SELECT, 1, stats); stats->totobj++; } } /* Statistics displayed in info header. Called regularly on scene changes. */ static void stats_update(Scene *scene) { SceneStats stats; Object *ob= (scene->basact)? scene->basact->object: NULL; Base *base; memset(&stats, 0, sizeof(stats)); if(scene->obedit) { /* Edit Mode */ stats_object_edit(scene->obedit, &stats); } else if(ob && (ob->mode & OB_MODE_POSE)) { /* Pose Mode */ stats_object_pose(ob, &stats); } else if(ob && (ob->flag & (OB_MODE_SCULPT|OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT))) { /* Sculpt and Paint Mode */ stats_object_paint(ob, &stats); } else { /* Objects */ for(base= scene->base.first; base; base=base->next) if(scene->lay & base->lay) stats_dupli_object(base, base->object, &stats); } if(!scene->stats) scene->stats= MEM_mallocN(sizeof(SceneStats), "SceneStats"); *(scene->stats)= stats; } static void stats_string(Scene *scene) { SceneStats *stats= scene->stats; Object *ob= (scene->basact)? scene->basact->object: NULL; uintptr_t mem_in_use, mmap_in_use; char memstr[64]; char *s; mem_in_use= MEM_get_memory_in_use(); mmap_in_use= MEM_get_mapped_memory_in_use(); /* get memory statistics */ s= memstr + sprintf(memstr, " | Mem:%.2fM", ((mem_in_use-mmap_in_use)>>10)/1024.0); if(mmap_in_use) sprintf(s, " (%.2fM)", ((mmap_in_use)>>10)/1024.0); s= stats->infostr; if(scene->obedit) { if(ob_get_keyblock(scene->obedit)) s+= sprintf(s, "(Key) "); if(scene->obedit->type==OB_MESH) { if(scene->toolsettings->selectmode & SCE_SELECT_VERTEX) s+= sprintf(s, "Ve:%d-%d | Ed:%d-%d | Fa:%d-%d", stats->totvertsel, stats->totvert, stats->totedgesel, stats->totedge, stats->totfacesel, stats->totface); else if(scene->toolsettings->selectmode & SCE_SELECT_EDGE) s+= sprintf(s, "Ed:%d-%d | Fa:%d-%d", stats->totedgesel, stats->totedge, stats->totfacesel, stats->totface); else s+= sprintf(s, "Fa:%d-%d", stats->totfacesel, stats->totface); } else if(scene->obedit->type==OB_ARMATURE) { s+= sprintf(s, "Ve:%d-%d | Bo:%d-%d", stats->totvertsel, stats->totvert, stats->totbonesel, stats->totbone); } else { s+= sprintf(s, "Ve:%d-%d", stats->totvertsel, stats->totvert); } strcat(s, memstr); } else if(ob && (ob->mode & OB_MODE_POSE)) { s += sprintf(s, "Bo:%d-%d %s", stats->totbonesel, stats->totbone, memstr); } else { s += sprintf(s, "Ve:%d | Fa:%d | Ob:%d-%d | La:%d%s", stats->totvert, stats->totface, stats->totobjsel, stats->totobj, stats->totlamp, memstr); } if(ob) sprintf(s, " | %s", ob->id.name+2); } void ED_info_stats_clear(Scene *scene) { if(scene->stats) { MEM_freeN(scene->stats); scene->stats= NULL; } } char *ED_info_stats_string(Scene *scene) { if(!scene->stats) stats_update(scene); stats_string(scene); return scene->stats->infostr; }