python api for collection add()/remove()
[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, sce, base) && 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 static int add_to_group_internal(Group *group, Object *ob)
157 {
158         GroupObject *go;
159         
160         if(group==NULL || ob==NULL) return 0;
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 0;
165         }
166         
167         go= MEM_callocN(sizeof(GroupObject), "groupobject");
168         BLI_addtail( &group->gobject, go);
169         
170         go->ob= ob;
171         
172         return 1;
173 }
174
175 int add_to_group(Group *group, Object *object, Scene *scene, Base *base)
176 {
177         if(add_to_group_internal(group, object)) {
178                 if((object->flag & OB_FROMGROUP)==0) {
179
180                         if(scene && base==NULL)
181                                 base= object_in_scene(object, scene);
182
183                         object->flag |= OB_FROMGROUP;
184
185                         if(base)
186                                 base->flag |= OB_FROMGROUP;
187                 }
188                 return 1;
189         }
190         else {
191                 return 0;
192         }
193 }
194
195 /* also used for ob==NULL */
196 static int rem_from_group_internal(Group *group, Object *ob)
197 {
198         GroupObject *go, *gon;
199         int removed = 0;
200         if(group==NULL) return 0;
201         
202         go= group->gobject.first;
203         while(go) {
204                 gon= go->next;
205                 if(go->ob==ob) {
206                         BLI_remlink(&group->gobject, go);
207                         free_group_object(go);
208                         removed = 1;
209                         /* should break here since an object being in a group twice cant happen? */
210                 }
211                 go= gon;
212         }
213         return removed;
214 }
215
216 int rem_from_group(Group *group, Object *object, Scene *scene, Base *base)
217 {
218         if(rem_from_group_internal(group, object)) {
219
220                 if(find_group(object, NULL) == NULL) {
221                         if(scene && base==NULL)
222                                 base= object_in_scene(object, scene);
223
224                         object->flag &= ~OB_FROMGROUP;
225
226                         if(base)
227                                 base->flag &= ~OB_FROMGROUP;
228                 }
229                 return 1;
230         }
231         else {
232                 return 0;
233         }
234 }
235
236 int object_in_group(Object *ob, Group *group)
237 {
238         GroupObject *go;
239         
240         if(group==NULL || ob==NULL) return 0;
241         
242         for(go= group->gobject.first; go; go= go->next) {
243                 if(go->ob==ob) 
244                         return 1;
245         }
246         return 0;
247 }
248
249 Group *find_group(Object *ob, Group *group)
250 {
251         if (group)
252                 group= group->id.next;
253         else
254                 group= G.main->group.first;
255         
256         while(group) {
257                 if(object_in_group(ob, group))
258                         return group;
259                 group= group->id.next;
260         }
261         return NULL;
262 }
263
264 void group_tag_recalc(Group *group)
265 {
266         GroupObject *go;
267         
268         if(group==NULL) return;
269         
270         for(go= group->gobject.first; go; go= go->next) {
271                 if(go->ob) 
272                         go->ob->recalc= go->recalc;
273         }
274 }
275
276 int group_is_animated(Object *parent, Group *group)
277 {
278         GroupObject *go;
279
280         if(give_timeoffset(parent) != 0.0f || parent->nlastrips.first)
281                 return 1;
282
283         for(go= group->gobject.first; go; go= go->next)
284                 if(go->ob && go->ob->proxy)
285                         return 1;
286
287         return 0;
288 }
289
290 /* only replaces object strips or action when parent nla instructs it */
291 /* keep checking nla.c though, in case internal structure of strip changes */
292 static void group_replaces_nla(Object *parent, Object *target, char mode)
293 {
294         static ListBase nlastrips={NULL, NULL};
295         static bAction *action= NULL;
296         static int done= 0;
297         bActionStrip *strip, *nstrip;
298         
299         if(mode=='s') {
300                 
301                 for(strip= parent->nlastrips.first; strip; strip= strip->next) {
302                         if(strip->object==target) {
303                                 if(done==0) {
304                                         /* clear nla & action from object */
305                                         nlastrips= target->nlastrips;
306                                         target->nlastrips.first= target->nlastrips.last= NULL;
307                                         action= target->action;
308                                         target->action= NULL;
309                                         target->nlaflag |= OB_NLA_OVERRIDE;
310                                         done= 1;
311                                 }
312                                 nstrip= MEM_dupallocN(strip);
313                                 BLI_addtail(&target->nlastrips, nstrip);
314                         }
315                 }
316         }
317         else if(mode=='e') {
318                 if(done) {
319                         BLI_freelistN(&target->nlastrips);
320                         target->nlastrips= nlastrips;
321                         target->action= action;
322                         
323                         nlastrips.first= nlastrips.last= NULL;  /* not needed, but yah... :) */
324                         action= NULL;
325                         done= 0;
326                 }
327         }
328 }
329
330 /* puts all group members in local timing system, after this call
331 you can draw everything, leaves tags in objects to signal it needs further updating */
332
333 /* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */
334 void group_handle_recalc_and_update(Scene *scene, Object *parent, Group *group)
335 {
336         GroupObject *go;
337         
338         /* if animated group... */
339         if(give_timeoffset(parent) != 0.0f || parent->nlastrips.first) {
340                 int cfrao;
341                 
342                 /* switch to local time */
343                 cfrao= scene->r.cfra;
344                 scene->r.cfra -= (int)give_timeoffset(parent);
345                 
346                 /* we need a DAG per group... */
347                 for(go= group->gobject.first; go; go= go->next) {
348                         if(go->ob && go->recalc) {
349                                 go->ob->recalc= go->recalc;
350                                 
351                                 group_replaces_nla(parent, go->ob, 's');
352                                 object_handle_update(scene, go->ob);
353                                 group_replaces_nla(parent, go->ob, 'e');
354                                 
355                                 /* leave recalc tags in case group members are in normal scene */
356                                 go->ob->recalc= go->recalc;
357                         }
358                 }
359                 
360                 /* restore */
361                 scene->r.cfra= cfrao;
362         }
363         else {
364                 /* only do existing tags, as set by regular depsgraph */
365                 for(go= group->gobject.first; go; go= go->next) {
366                         if(go->ob) {
367                                 if(go->ob->recalc) {
368                                         object_handle_update(scene, go->ob);
369                                 }
370                         }
371                 }
372         }
373 }
374
375 Object *group_get_member_with_action(Group *group, bAction *act)
376 {
377         GroupObject *go;
378         
379         if(group==NULL || act==NULL) return NULL;
380         
381         for(go= group->gobject.first; go; go= go->next) {
382                 if(go->ob) {
383                         if(go->ob->action==act)
384                                 return go->ob;
385                         if(go->ob->nlastrips.first) {
386                                 bActionStrip *strip;
387                                 
388                                 for(strip= go->ob->nlastrips.first; strip; strip= strip->next) {
389                                         if(strip->act==act)
390                                                 return go->ob;
391                                 }
392                         }
393                 }
394         }
395         return NULL;
396 }
397
398 /* if group has NLA, we try to map the used objects in NLA to group members */
399 /* this assuming that object has received a new group link */
400 void group_relink_nla_objects(Object *ob)
401 {
402         Group *group;
403         GroupObject *go;
404         bActionStrip *strip;
405         
406         if(ob==NULL || ob->dup_group==NULL) return;
407         group= ob->dup_group;
408         
409         for(strip= ob->nlastrips.first; strip; strip= strip->next) {
410                 if(strip->object) {
411                         for(go= group->gobject.first; go; go= go->next) {
412                                 if(go->ob) {
413                                         if(strcmp(go->ob->id.name, strip->object->id.name)==0)
414                                                 break;
415                                 }
416                         }
417                         if(go)
418                                 strip->object= go->ob;
419                         else
420                                 strip->object= NULL;
421                 }
422                         
423         }
424 }
425