doxygen: blender/blenkernel tagged.
[blender.git] / source / blender / blenkernel / intern / group.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  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 /** \file blender/blenkernel/intern/group.c
31  *  \ingroup bke
32  */
33
34
35 #include <stdio.h>
36 #include <string.h>
37 #include <math.h>
38
39 #include "MEM_guardedalloc.h"
40
41 #include "DNA_group_types.h"
42 #include "DNA_material_types.h"
43 #include "DNA_object_types.h"
44 #include "DNA_nla_types.h"
45 #include "DNA_scene_types.h"
46 #include "DNA_particle_types.h"
47
48 #include "BLI_blenlib.h"
49 #include "BLI_utildefines.h"
50
51
52 #include "BKE_global.h"
53 #include "BKE_group.h"
54 #include "BKE_library.h"
55 #include "BKE_main.h"
56 #include "BKE_object.h"
57 #include "BKE_scene.h" /* object_in_scene */
58
59 static void free_group_object(GroupObject *go)
60 {
61         MEM_freeN(go);
62 }
63
64
65 void free_group_objects(Group *group)
66 {
67         /* don't free group itself */
68         GroupObject *go;
69         
70         while(group->gobject.first) {
71                 go= group->gobject.first;
72                 BLI_remlink(&group->gobject, go);
73                 free_group_object(go);
74         }
75 }
76
77 void unlink_group(Group *group)
78 {
79         Main *bmain= G.main;
80         Material *ma;
81         Object *ob;
82         Scene *sce;
83         SceneRenderLayer *srl;
84         ParticleSystem *psys;
85         
86         for(ma= bmain->mat.first; ma; ma= ma->id.next) {
87                 if(ma->group==group)
88                         ma->group= NULL;
89         }
90         for(ma= bmain->mat.first; ma; ma= ma->id.next) {
91                 if(ma->group==group)
92                         ma->group= NULL;
93         }
94         for (sce= bmain->scene.first; sce; sce= sce->id.next) {
95                 Base *base= sce->base.first;
96                 
97                 /* ensure objects are not in this group */
98                 for(; base; base= base->next) {
99                         if(rem_from_group(group, base->object, sce, base) && find_group(base->object, NULL)==NULL) {
100                                 base->object->flag &= ~OB_FROMGROUP;
101                                 base->flag &= ~OB_FROMGROUP;
102                         }
103                 }                       
104                 
105                 for(srl= sce->r.layers.first; srl; srl= srl->next) {
106                         if (srl->light_override==group)
107                                 srl->light_override= NULL;
108                 }
109         }
110         
111         for(ob= bmain->object.first; ob; ob= ob->id.next) {
112                 bActionStrip *strip;
113                 
114                 if(ob->dup_group==group) {
115                         ob->dup_group= NULL;
116                 
117                         /* duplicator strips use a group object, we remove it */
118                         for(strip= ob->nlastrips.first; strip; strip= strip->next) {
119                                 if(strip->object)
120                                         strip->object= NULL;
121                         }
122                 }
123                 
124                 for(psys=ob->particlesystem.first; psys; psys=psys->next){
125                         if(psys->part->dup_group==group)
126                                 psys->part->dup_group= NULL;
127                         if(psys->part->eff_group==group)
128                                 psys->part->eff_group= NULL;
129                 }
130         }
131         
132         /* group stays in library, but no members */
133         free_group_objects(group);
134         group->id.us= 0;
135 }
136
137 Group *add_group(const char *name)
138 {
139         Group *group;
140         
141         group = alloc_libblock(&G.main->group, ID_GR, name);
142         group->layer= (1<<20)-1;
143         return group;
144 }
145
146 Group *copy_group(Group *group)
147 {
148         Group *groupn;
149
150         groupn= MEM_dupallocN(group);
151         BLI_duplicatelist(&groupn->gobject, &group->gobject);
152
153         return groupn;
154 }
155
156 /* external */
157 static int add_to_group_internal(Group *group, Object *ob)
158 {
159         GroupObject *go;
160         
161         if(group==NULL || ob==NULL) return 0;
162         
163         /* check if the object has been added already */
164         for(go= group->gobject.first; go; go= go->next) {
165                 if(go->ob==ob) return 0;
166         }
167         
168         go= MEM_callocN(sizeof(GroupObject), "groupobject");
169         BLI_addtail( &group->gobject, go);
170         
171         go->ob= ob;
172         
173         return 1;
174 }
175
176 int add_to_group(Group *group, Object *object, Scene *scene, Base *base)
177 {
178         if(add_to_group_internal(group, object)) {
179                 if((object->flag & OB_FROMGROUP)==0) {
180
181                         if(scene && base==NULL)
182                                 base= object_in_scene(object, scene);
183
184                         object->flag |= OB_FROMGROUP;
185
186                         if(base)
187                                 base->flag |= OB_FROMGROUP;
188                 }
189                 return 1;
190         }
191         else {
192                 return 0;
193         }
194 }
195
196 /* also used for ob==NULL */
197 static int rem_from_group_internal(Group *group, Object *ob)
198 {
199         GroupObject *go, *gon;
200         int removed = 0;
201         if(group==NULL) return 0;
202         
203         go= group->gobject.first;
204         while(go) {
205                 gon= go->next;
206                 if(go->ob==ob) {
207                         BLI_remlink(&group->gobject, go);
208                         free_group_object(go);
209                         removed = 1;
210                         /* should break here since an object being in a group twice cant happen? */
211                 }
212                 go= gon;
213         }
214         return removed;
215 }
216
217 int rem_from_group(Group *group, Object *object, Scene *scene, Base *base)
218 {
219         if(rem_from_group_internal(group, object)) {
220                 /* object can be NULL */
221                 if(object && find_group(object, NULL) == NULL) {
222                         if(scene && base==NULL)
223                                 base= object_in_scene(object, scene);
224
225                         object->flag &= ~OB_FROMGROUP;
226
227                         if(base)
228                                 base->flag &= ~OB_FROMGROUP;
229                 }
230                 return 1;
231         }
232         else {
233                 return 0;
234         }
235 }
236
237 int object_in_group(Object *ob, Group *group)
238 {
239         GroupObject *go;
240         
241         if(group==NULL || ob==NULL) return 0;
242         
243         for(go= group->gobject.first; go; go= go->next) {
244                 if(go->ob==ob) 
245                         return 1;
246         }
247         return 0;
248 }
249
250 Group *find_group(Object *ob, Group *group)
251 {
252         if (group)
253                 group= group->id.next;
254         else
255                 group= G.main->group.first;
256         
257         while(group) {
258                 if(object_in_group(ob, group))
259                         return group;
260                 group= group->id.next;
261         }
262         return NULL;
263 }
264
265 void group_tag_recalc(Group *group)
266 {
267         GroupObject *go;
268         
269         if(group==NULL) return;
270         
271         for(go= group->gobject.first; go; go= go->next) {
272                 if(go->ob) 
273                         go->ob->recalc= go->recalc;
274         }
275 }
276
277 int group_is_animated(Object *parent, Group *group)
278 {
279         GroupObject *go;
280
281         if(give_timeoffset(parent) != 0.0f || parent->nlastrips.first)
282                 return 1;
283
284         for(go= group->gobject.first; go; go= go->next)
285                 if(go->ob && go->ob->proxy)
286                         return 1;
287
288         return 0;
289 }
290
291 #if 0 // add back when timeoffset & animsys work again
292 /* only replaces object strips or action when parent nla instructs it */
293 /* keep checking nla.c though, in case internal structure of strip changes */
294 static void group_replaces_nla(Object *parent, Object *target, char mode)
295 {
296         static ListBase nlastrips={NULL, NULL};
297         static bAction *action= NULL;
298         static int done= 0;
299         bActionStrip *strip, *nstrip;
300         
301         if(mode=='s') {
302                 
303                 for(strip= parent->nlastrips.first; strip; strip= strip->next) {
304                         if(strip->object==target) {
305                                 if(done==0) {
306                                         /* clear nla & action from object */
307                                         nlastrips= target->nlastrips;
308                                         target->nlastrips.first= target->nlastrips.last= NULL;
309                                         action= target->action;
310                                         target->action= NULL;
311                                         target->nlaflag |= OB_NLA_OVERRIDE;
312                                         done= 1;
313                                 }
314                                 nstrip= MEM_dupallocN(strip);
315                                 BLI_addtail(&target->nlastrips, nstrip);
316                         }
317                 }
318         }
319         else if(mode=='e') {
320                 if(done) {
321                         BLI_freelistN(&target->nlastrips);
322                         target->nlastrips= nlastrips;
323                         target->action= action;
324                         
325                         nlastrips.first= nlastrips.last= NULL;  /* not needed, but yah... :) */
326                         action= NULL;
327                         done= 0;
328                 }
329         }
330 }
331 #endif
332
333 /* puts all group members in local timing system, after this call
334 you can draw everything, leaves tags in objects to signal it needs further updating */
335
336 /* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */
337 void group_handle_recalc_and_update(Scene *scene, Object *UNUSED(parent), Group *group)
338 {
339         GroupObject *go;
340         
341 #if 0 /* warning, isnt clearing the recalc flag on the object which causes it to run all the time,
342            * not just on frame change.
343            * This isnt working because the animation data is only re-evalyated on frame change so commenting for now
344            * but when its enabled at some point it will need to be changed so as not to update so much - campbell */
345
346         /* if animated group... */
347         if(give_timeoffset(parent) != 0.0f || parent->nlastrips.first) {
348                 int cfrao;
349                 
350                 /* switch to local time */
351                 cfrao= scene->r.cfra;
352                 scene->r.cfra -= (int)floor(give_timeoffset(parent) + 0.5f);
353                 
354                 /* we need a DAG per group... */
355                 for(go= group->gobject.first; go; go= go->next) {
356                         if(go->ob && go->recalc) {
357                                 go->ob->recalc= go->recalc;
358                                 
359                                 group_replaces_nla(parent, go->ob, 's');
360                                 object_handle_update(scene, go->ob);
361                                 group_replaces_nla(parent, go->ob, 'e');
362                                 
363                                 /* leave recalc tags in case group members are in normal scene */
364                                 go->ob->recalc= go->recalc;
365                         }
366                 }
367                 
368                 /* restore */
369                 scene->r.cfra= cfrao;
370         }
371         else
372 #endif
373         {
374                 /* only do existing tags, as set by regular depsgraph */
375                 for(go= group->gobject.first; go; go= go->next) {
376                         if(go->ob) {
377                                 if(go->ob->recalc) {
378                                         object_handle_update(scene, go->ob);
379                                 }
380                         }
381                 }
382         }
383 }
384
385 Object *group_get_member_with_action(Group *group, bAction *act)
386 {
387         GroupObject *go;
388         
389         if(group==NULL || act==NULL) return NULL;
390         
391         for(go= group->gobject.first; go; go= go->next) {
392                 if(go->ob) {
393                         if(go->ob->action==act)
394                                 return go->ob;
395                         if(go->ob->nlastrips.first) {
396                                 bActionStrip *strip;
397                                 
398                                 for(strip= go->ob->nlastrips.first; strip; strip= strip->next) {
399                                         if(strip->act==act)
400                                                 return go->ob;
401                                 }
402                         }
403                 }
404         }
405         return NULL;
406 }
407
408 /* if group has NLA, we try to map the used objects in NLA to group members */
409 /* this assuming that object has received a new group link */
410 void group_relink_nla_objects(Object *ob)
411 {
412         Group *group;
413         GroupObject *go;
414         bActionStrip *strip;
415         
416         if(ob==NULL || ob->dup_group==NULL) return;
417         group= ob->dup_group;
418         
419         for(strip= ob->nlastrips.first; strip; strip= strip->next) {
420                 if(strip->object) {
421                         for(go= group->gobject.first; go; go= go->next) {
422                                 if(go->ob) {
423                                         if(strcmp(go->ob->id.name, strip->object->id.name)==0)
424                                                 break;
425                                 }
426                         }
427                         if(go)
428                                 strip->object= go->ob;
429                         else
430                                 strip->object= NULL;
431                 }
432                         
433         }
434 }
435