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