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