Blender  V2.59
group.c
Go to the documentation of this file.
00001 /* 
00002  * $Id: group.c 35247 2011-02-27 20:40:57Z jesterking $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00021  * All rights reserved.
00022  *
00023  * The Original Code is: all of this file.
00024  *
00025  * Contributor(s): none yet.
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  */
00029 
00035 #include <stdio.h>
00036 #include <string.h>
00037 #include <math.h>
00038 
00039 #include "MEM_guardedalloc.h"
00040 
00041 #include "DNA_group_types.h"
00042 #include "DNA_material_types.h"
00043 #include "DNA_object_types.h"
00044 #include "DNA_nla_types.h"
00045 #include "DNA_scene_types.h"
00046 #include "DNA_particle_types.h"
00047 
00048 #include "BLI_blenlib.h"
00049 #include "BLI_utildefines.h"
00050 
00051 
00052 #include "BKE_global.h"
00053 #include "BKE_group.h"
00054 #include "BKE_library.h"
00055 #include "BKE_main.h"
00056 #include "BKE_object.h"
00057 #include "BKE_scene.h" /* object_in_scene */
00058 
00059 static void free_group_object(GroupObject *go)
00060 {
00061         MEM_freeN(go);
00062 }
00063 
00064 
00065 void free_group_objects(Group *group)
00066 {
00067         /* don't free group itself */
00068         GroupObject *go;
00069         
00070         while(group->gobject.first) {
00071                 go= group->gobject.first;
00072                 BLI_remlink(&group->gobject, go);
00073                 free_group_object(go);
00074         }
00075 }
00076 
00077 void unlink_group(Group *group)
00078 {
00079         Main *bmain= G.main;
00080         Material *ma;
00081         Object *ob;
00082         Scene *sce;
00083         SceneRenderLayer *srl;
00084         ParticleSystem *psys;
00085         
00086         for(ma= bmain->mat.first; ma; ma= ma->id.next) {
00087                 if(ma->group==group)
00088                         ma->group= NULL;
00089         }
00090         for(ma= bmain->mat.first; ma; ma= ma->id.next) {
00091                 if(ma->group==group)
00092                         ma->group= NULL;
00093         }
00094         for (sce= bmain->scene.first; sce; sce= sce->id.next) {
00095                 Base *base= sce->base.first;
00096                 
00097                 /* ensure objects are not in this group */
00098                 for(; base; base= base->next) {
00099                         if(rem_from_group(group, base->object, sce, base) && find_group(base->object, NULL)==NULL) {
00100                                 base->object->flag &= ~OB_FROMGROUP;
00101                                 base->flag &= ~OB_FROMGROUP;
00102                         }
00103                 }                       
00104                 
00105                 for(srl= sce->r.layers.first; srl; srl= srl->next) {
00106                         if (srl->light_override==group)
00107                                 srl->light_override= NULL;
00108                 }
00109         }
00110         
00111         for(ob= bmain->object.first; ob; ob= ob->id.next) {
00112                 bActionStrip *strip;
00113                 
00114                 if(ob->dup_group==group) {
00115                         ob->dup_group= NULL;
00116                 
00117                         /* duplicator strips use a group object, we remove it */
00118                         for(strip= ob->nlastrips.first; strip; strip= strip->next) {
00119                                 if(strip->object)
00120                                         strip->object= NULL;
00121                         }
00122                 }
00123                 
00124                 for(psys=ob->particlesystem.first; psys; psys=psys->next){
00125                         if(psys->part->dup_group==group)
00126                                 psys->part->dup_group= NULL;
00127                         if(psys->part->eff_group==group)
00128                                 psys->part->eff_group= NULL;
00129                 }
00130         }
00131         
00132         /* group stays in library, but no members */
00133         free_group_objects(group);
00134         group->id.us= 0;
00135 }
00136 
00137 Group *add_group(const char *name)
00138 {
00139         Group *group;
00140         
00141         group = alloc_libblock(&G.main->group, ID_GR, name);
00142         group->layer= (1<<20)-1;
00143         return group;
00144 }
00145 
00146 Group *copy_group(Group *group)
00147 {
00148         Group *groupn;
00149 
00150         groupn= MEM_dupallocN(group);
00151         BLI_duplicatelist(&groupn->gobject, &group->gobject);
00152 
00153         return groupn;
00154 }
00155 
00156 /* external */
00157 static int add_to_group_internal(Group *group, Object *ob)
00158 {
00159         GroupObject *go;
00160         
00161         if(group==NULL || ob==NULL) return 0;
00162         
00163         /* check if the object has been added already */
00164         for(go= group->gobject.first; go; go= go->next) {
00165                 if(go->ob==ob) return 0;
00166         }
00167         
00168         go= MEM_callocN(sizeof(GroupObject), "groupobject");
00169         BLI_addtail( &group->gobject, go);
00170         
00171         go->ob= ob;
00172         
00173         return 1;
00174 }
00175 
00176 int add_to_group(Group *group, Object *object, Scene *scene, Base *base)
00177 {
00178         if(add_to_group_internal(group, object)) {
00179                 if((object->flag & OB_FROMGROUP)==0) {
00180 
00181                         if(scene && base==NULL)
00182                                 base= object_in_scene(object, scene);
00183 
00184                         object->flag |= OB_FROMGROUP;
00185 
00186                         if(base)
00187                                 base->flag |= OB_FROMGROUP;
00188                 }
00189                 return 1;
00190         }
00191         else {
00192                 return 0;
00193         }
00194 }
00195 
00196 /* also used for ob==NULL */
00197 static int rem_from_group_internal(Group *group, Object *ob)
00198 {
00199         GroupObject *go, *gon;
00200         int removed = 0;
00201         if(group==NULL) return 0;
00202         
00203         go= group->gobject.first;
00204         while(go) {
00205                 gon= go->next;
00206                 if(go->ob==ob) {
00207                         BLI_remlink(&group->gobject, go);
00208                         free_group_object(go);
00209                         removed = 1;
00210                         /* should break here since an object being in a group twice cant happen? */
00211                 }
00212                 go= gon;
00213         }
00214         return removed;
00215 }
00216 
00217 int rem_from_group(Group *group, Object *object, Scene *scene, Base *base)
00218 {
00219         if(rem_from_group_internal(group, object)) {
00220                 /* object can be NULL */
00221                 if(object && find_group(object, NULL) == NULL) {
00222                         if(scene && base==NULL)
00223                                 base= object_in_scene(object, scene);
00224 
00225                         object->flag &= ~OB_FROMGROUP;
00226 
00227                         if(base)
00228                                 base->flag &= ~OB_FROMGROUP;
00229                 }
00230                 return 1;
00231         }
00232         else {
00233                 return 0;
00234         }
00235 }
00236 
00237 int object_in_group(Object *ob, Group *group)
00238 {
00239         GroupObject *go;
00240         
00241         if(group==NULL || ob==NULL) return 0;
00242         
00243         for(go= group->gobject.first; go; go= go->next) {
00244                 if(go->ob==ob) 
00245                         return 1;
00246         }
00247         return 0;
00248 }
00249 
00250 Group *find_group(Object *ob, Group *group)
00251 {
00252         if (group)
00253                 group= group->id.next;
00254         else
00255                 group= G.main->group.first;
00256         
00257         while(group) {
00258                 if(object_in_group(ob, group))
00259                         return group;
00260                 group= group->id.next;
00261         }
00262         return NULL;
00263 }
00264 
00265 void group_tag_recalc(Group *group)
00266 {
00267         GroupObject *go;
00268         
00269         if(group==NULL) return;
00270         
00271         for(go= group->gobject.first; go; go= go->next) {
00272                 if(go->ob) 
00273                         go->ob->recalc= go->recalc;
00274         }
00275 }
00276 
00277 int group_is_animated(Object *parent, Group *group)
00278 {
00279         GroupObject *go;
00280 
00281         if(give_timeoffset(parent) != 0.0f || parent->nlastrips.first)
00282                 return 1;
00283 
00284         for(go= group->gobject.first; go; go= go->next)
00285                 if(go->ob && go->ob->proxy)
00286                         return 1;
00287 
00288         return 0;
00289 }
00290 
00291 #if 0 // add back when timeoffset & animsys work again
00292 /* only replaces object strips or action when parent nla instructs it */
00293 /* keep checking nla.c though, in case internal structure of strip changes */
00294 static void group_replaces_nla(Object *parent, Object *target, char mode)
00295 {
00296         static ListBase nlastrips={NULL, NULL};
00297         static bAction *action= NULL;
00298         static int done= 0;
00299         bActionStrip *strip, *nstrip;
00300         
00301         if(mode=='s') {
00302                 
00303                 for(strip= parent->nlastrips.first; strip; strip= strip->next) {
00304                         if(strip->object==target) {
00305                                 if(done==0) {
00306                                         /* clear nla & action from object */
00307                                         nlastrips= target->nlastrips;
00308                                         target->nlastrips.first= target->nlastrips.last= NULL;
00309                                         action= target->action;
00310                                         target->action= NULL;
00311                                         target->nlaflag |= OB_NLA_OVERRIDE;
00312                                         done= 1;
00313                                 }
00314                                 nstrip= MEM_dupallocN(strip);
00315                                 BLI_addtail(&target->nlastrips, nstrip);
00316                         }
00317                 }
00318         }
00319         else if(mode=='e') {
00320                 if(done) {
00321                         BLI_freelistN(&target->nlastrips);
00322                         target->nlastrips= nlastrips;
00323                         target->action= action;
00324                         
00325                         nlastrips.first= nlastrips.last= NULL;  /* not needed, but yah... :) */
00326                         action= NULL;
00327                         done= 0;
00328                 }
00329         }
00330 }
00331 #endif
00332 
00333 /* puts all group members in local timing system, after this call
00334 you can draw everything, leaves tags in objects to signal it needs further updating */
00335 
00336 /* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */
00337 void group_handle_recalc_and_update(Scene *scene, Object *UNUSED(parent), Group *group)
00338 {
00339         GroupObject *go;
00340         
00341 #if 0 /* warning, isnt clearing the recalc flag on the object which causes it to run all the time,
00342            * not just on frame change.
00343            * This isnt working because the animation data is only re-evalyated on frame change so commenting for now
00344            * but when its enabled at some point it will need to be changed so as not to update so much - campbell */
00345 
00346         /* if animated group... */
00347         if(give_timeoffset(parent) != 0.0f || parent->nlastrips.first) {
00348                 int cfrao;
00349                 
00350                 /* switch to local time */
00351                 cfrao= scene->r.cfra;
00352                 scene->r.cfra -= (int)floor(give_timeoffset(parent) + 0.5f);
00353                 
00354                 /* we need a DAG per group... */
00355                 for(go= group->gobject.first; go; go= go->next) {
00356                         if(go->ob && go->recalc) {
00357                                 go->ob->recalc= go->recalc;
00358                                 
00359                                 group_replaces_nla(parent, go->ob, 's');
00360                                 object_handle_update(scene, go->ob);
00361                                 group_replaces_nla(parent, go->ob, 'e');
00362                                 
00363                                 /* leave recalc tags in case group members are in normal scene */
00364                                 go->ob->recalc= go->recalc;
00365                         }
00366                 }
00367                 
00368                 /* restore */
00369                 scene->r.cfra= cfrao;
00370         }
00371         else
00372 #endif
00373         {
00374                 /* only do existing tags, as set by regular depsgraph */
00375                 for(go= group->gobject.first; go; go= go->next) {
00376                         if(go->ob) {
00377                                 if(go->ob->recalc) {
00378                                         object_handle_update(scene, go->ob);
00379                                 }
00380                         }
00381                 }
00382         }
00383 }
00384 
00385 Object *group_get_member_with_action(Group *group, bAction *act)
00386 {
00387         GroupObject *go;
00388         
00389         if(group==NULL || act==NULL) return NULL;
00390         
00391         for(go= group->gobject.first; go; go= go->next) {
00392                 if(go->ob) {
00393                         if(go->ob->action==act)
00394                                 return go->ob;
00395                         if(go->ob->nlastrips.first) {
00396                                 bActionStrip *strip;
00397                                 
00398                                 for(strip= go->ob->nlastrips.first; strip; strip= strip->next) {
00399                                         if(strip->act==act)
00400                                                 return go->ob;
00401                                 }
00402                         }
00403                 }
00404         }
00405         return NULL;
00406 }
00407 
00408 /* if group has NLA, we try to map the used objects in NLA to group members */
00409 /* this assuming that object has received a new group link */
00410 void group_relink_nla_objects(Object *ob)
00411 {
00412         Group *group;
00413         GroupObject *go;
00414         bActionStrip *strip;
00415         
00416         if(ob==NULL || ob->dup_group==NULL) return;
00417         group= ob->dup_group;
00418         
00419         for(strip= ob->nlastrips.first; strip; strip= strip->next) {
00420                 if(strip->object) {
00421                         for(go= group->gobject.first; go; go= go->next) {
00422                                 if(go->ob) {
00423                                         if(strcmp(go->ob->id.name, strip->object->id.name)==0)
00424                                                 break;
00425                                 }
00426                         }
00427                         if(go)
00428                                 strip->object= go->ob;
00429                         else
00430                                 strip->object= NULL;
00431                 }
00432                         
00433         }
00434 }
00435