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