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