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