Merged changes in the trunk up to revision 55357.
[blender-staging.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" /* BKE_scene_base_find */
56
57 static void free_group_object(GroupObject *go)
58 {
59         MEM_freeN(go);
60 }
61
62
63 void BKE_group_free(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 BKE_group_unlink(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 #ifdef WITH_FREESTYLE
108                         {
109                                 FreestyleLineSet *lineset;
110                                 for(lineset = srl->freestyleConfig.linesets.first; lineset; lineset= lineset->next) {
111                                         if (lineset->group == group)
112                                                 lineset->group = NULL;
113                                 }
114                         }
115 #endif
116                 }
117         }
118         
119         for (ob = bmain->object.first; ob; ob = ob->id.next) {
120                 
121                 if (ob->dup_group == group) {
122                         ob->dup_group = NULL;
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         BKE_group_free(group);
137         group->id.us = 0;
138 }
139
140 Group *add_group(Main *bmain, const char *name)
141 {
142         Group *group;
143         
144         group = BKE_libblock_alloc(&bmain->group, ID_GR, name);
145         group->layer = (1 << 20) - 1;
146         return group;
147 }
148
149 Group *BKE_group_copy(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) {
165                 return FALSE;
166         }
167         
168         /* check if the object has been added already */
169         if (BLI_findptr(&group->gobject, ob, offsetof(GroupObject, ob))) {
170                 return FALSE;
171         }
172         
173         go = MEM_callocN(sizeof(GroupObject), "groupobject");
174         BLI_addtail(&group->gobject, go);
175         
176         go->ob = ob;
177         
178         return TRUE;
179 }
180
181 int add_to_group(Group *group, Object *object, Scene *scene, Base *base)
182 {
183         if (add_to_group_internal(group, object)) {
184                 if ((object->flag & OB_FROMGROUP) == 0) {
185
186                         if (scene && base == NULL)
187                                 base = BKE_scene_base_find(scene, object);
188
189                         object->flag |= OB_FROMGROUP;
190
191                         if (base)
192                                 base->flag |= OB_FROMGROUP;
193                 }
194                 return 1;
195         }
196         else {
197                 return 0;
198         }
199 }
200
201 /* also used for (ob == NULL) */
202 static int rem_from_group_internal(Group *group, Object *ob)
203 {
204         GroupObject *go, *gon;
205         int removed = 0;
206         if (group == NULL) return 0;
207         
208         go = group->gobject.first;
209         while (go) {
210                 gon = go->next;
211                 if (go->ob == ob) {
212                         BLI_remlink(&group->gobject, go);
213                         free_group_object(go);
214                         removed = 1;
215                         /* should break here since an object being in a group twice cant happen? */
216                 }
217                 go = gon;
218         }
219         return removed;
220 }
221
222 int rem_from_group(Group *group, Object *object, Scene *scene, Base *base)
223 {
224         if (rem_from_group_internal(group, object)) {
225                 /* object can be NULL */
226                 if (object && find_group(object, NULL) == NULL) {
227                         if (scene && base == NULL)
228                                 base = BKE_scene_base_find(scene, object);
229
230                         object->flag &= ~OB_FROMGROUP;
231
232                         if (base)
233                                 base->flag &= ~OB_FROMGROUP;
234                 }
235                 return 1;
236         }
237         else {
238                 return 0;
239         }
240 }
241
242 int object_in_group(Object *ob, Group *group)
243 {
244         if (group == NULL || ob == NULL) {
245                 return FALSE;
246         }
247
248         return (BLI_findptr(&group->gobject, ob, offsetof(GroupObject, ob)) != NULL);
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 *UNUSED(parent), Group *group)
279 {
280         GroupObject *go;
281
282 #if 0 /* XXX OLD ANIMSYS, NLASTRIPS ARE NO LONGER USED */
283         if (parent->nlastrips.first)
284                 return 1;
285 #endif
286
287         for (go = group->gobject.first; go; go = go->next)
288                 if (go->ob && go->ob->proxy)
289                         return 1;
290
291         return 0;
292 }
293
294 #if 0 // add back when timeoffset & animsys work again
295 /* only replaces object strips or action when parent nla instructs it */
296 /* keep checking nla.c though, in case internal structure of strip changes */
297 static void group_replaces_nla(Object *parent, Object *target, char mode)
298 {
299         static ListBase nlastrips = {NULL, NULL};
300         static bAction *action = NULL;
301         static int done = FALSE;
302         bActionStrip *strip, *nstrip;
303         
304         if (mode == 's') {
305                 
306                 for (strip = parent->nlastrips.first; strip; strip = strip->next) {
307                         if (strip->object == target) {
308                                 if (done == 0) {
309                                         /* clear nla & action from object */
310                                         nlastrips = target->nlastrips;
311                                         target->nlastrips.first = target->nlastrips.last = NULL;
312                                         action = target->action;
313                                         target->action = NULL;
314                                         target->nlaflag |= OB_NLA_OVERRIDE;
315                                         done = TRUE;
316                                 }
317                                 nstrip = MEM_dupallocN(strip);
318                                 BLI_addtail(&target->nlastrips, nstrip);
319                         }
320                 }
321         }
322         else if (mode == 'e') {
323                 if (done) {
324                         BLI_freelistN(&target->nlastrips);
325                         target->nlastrips = nlastrips;
326                         target->action = action;
327                         
328                         nlastrips.first = nlastrips.last = NULL;  /* not needed, but yah... :) */
329                         action = NULL;
330                         done = FALSE;
331                 }
332         }
333 }
334 #endif
335
336 /* puts all group members in local timing system, after this call
337  * you can draw everything, leaves tags in objects to signal it needs further updating */
338
339 /* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */
340 void group_handle_recalc_and_update(Scene *scene, Object *UNUSED(parent), Group *group)
341 {
342         GroupObject *go;
343         
344 #if 0 /* warning, isn't clearing the recalc flag on the object which causes it to run all the time,
345            * not just on frame change.
346            * This isn't working because the animation data is only re-evaluated on frame change so commenting for now
347            * but when its enabled at some point it will need to be changed so as not to update so much - campbell */
348
349         /* if animated group... */
350         if (parent->nlastrips.first) {
351                 int cfrao;
352                 
353                 /* switch to local time */
354                 cfrao = scene->r.cfra;
355                 
356                 /* we need a DAG per group... */
357                 for (go = group->gobject.first; go; go = go->next) {
358                         if (go->ob && go->recalc) {
359                                 go->ob->recalc = go->recalc;
360                                 
361                                 group_replaces_nla(parent, go->ob, 's');
362                                 BKE_object_handle_update(scene, go->ob);
363                                 group_replaces_nla(parent, go->ob, 'e');
364                                 
365                                 /* leave recalc tags in case group members are in normal scene */
366                                 go->ob->recalc = go->recalc;
367                         }
368                 }
369                 
370                 /* restore */
371                 scene->r.cfra = cfrao;
372         }
373         else
374 #endif
375         {
376                 /* only do existing tags, as set by regular depsgraph */
377                 for (go = group->gobject.first; go; go = go->next) {
378                         if (go->ob) {
379                                 if (go->ob->recalc) {
380                                         BKE_object_handle_update(scene, go->ob);
381                                 }
382                         }
383                 }
384         }
385 }