Patch #34204: [Render Animation] Fails with "Error: Specified sample_fmt is not suppo...
[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" /* 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         }
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                 }
114                 
115                 for (psys = ob->particlesystem.first; psys; psys = psys->next) {
116                         if (psys->part->dup_group == group)
117                                 psys->part->dup_group = NULL;
118 #if 0       /* not used anymore, only keps for readfile.c, no need to account for this */
119                         if (psys->part->eff_group == group)
120                                 psys->part->eff_group = NULL;
121 #endif
122                 }
123         }
124         
125         /* group stays in library, but no members */
126         BKE_group_free(group);
127         group->id.us = 0;
128 }
129
130 Group *add_group(Main *bmain, const char *name)
131 {
132         Group *group;
133         
134         group = BKE_libblock_alloc(&bmain->group, ID_GR, name);
135         group->layer = (1 << 20) - 1;
136         return group;
137 }
138
139 Group *BKE_group_copy(Group *group)
140 {
141         Group *groupn;
142
143         groupn = MEM_dupallocN(group);
144         BLI_duplicatelist(&groupn->gobject, &group->gobject);
145
146         return groupn;
147 }
148
149 /* external */
150 static int add_to_group_internal(Group *group, Object *ob)
151 {
152         GroupObject *go;
153         
154         if (group == NULL || ob == NULL) {
155                 return FALSE;
156         }
157         
158         /* check if the object has been added already */
159         if (BLI_findptr(&group->gobject, ob, offsetof(GroupObject, ob))) {
160                 return FALSE;
161         }
162         
163         go = MEM_callocN(sizeof(GroupObject), "groupobject");
164         BLI_addtail(&group->gobject, go);
165         
166         go->ob = ob;
167         
168         return TRUE;
169 }
170
171 int add_to_group(Group *group, Object *object, Scene *scene, Base *base)
172 {
173         if (add_to_group_internal(group, object)) {
174                 if ((object->flag & OB_FROMGROUP) == 0) {
175
176                         if (scene && base == NULL)
177                                 base = BKE_scene_base_find(scene, object);
178
179                         object->flag |= OB_FROMGROUP;
180
181                         if (base)
182                                 base->flag |= OB_FROMGROUP;
183                 }
184                 return 1;
185         }
186         else {
187                 return 0;
188         }
189 }
190
191 /* also used for (ob == NULL) */
192 static int rem_from_group_internal(Group *group, Object *ob)
193 {
194         GroupObject *go, *gon;
195         int removed = 0;
196         if (group == NULL) return 0;
197         
198         go = group->gobject.first;
199         while (go) {
200                 gon = go->next;
201                 if (go->ob == ob) {
202                         BLI_remlink(&group->gobject, go);
203                         free_group_object(go);
204                         removed = 1;
205                         /* should break here since an object being in a group twice cant happen? */
206                 }
207                 go = gon;
208         }
209         return removed;
210 }
211
212 int rem_from_group(Group *group, Object *object, Scene *scene, Base *base)
213 {
214         if (rem_from_group_internal(group, object)) {
215                 /* object can be NULL */
216                 if (object && find_group(object, NULL) == NULL) {
217                         if (scene && base == NULL)
218                                 base = BKE_scene_base_find(scene, object);
219
220                         object->flag &= ~OB_FROMGROUP;
221
222                         if (base)
223                                 base->flag &= ~OB_FROMGROUP;
224                 }
225                 return 1;
226         }
227         else {
228                 return 0;
229         }
230 }
231
232 int object_in_group(Object *ob, Group *group)
233 {
234         if (group == NULL || ob == NULL) {
235                 return FALSE;
236         }
237
238         return (BLI_findptr(&group->gobject, ob, offsetof(GroupObject, ob)) != NULL);
239 }
240
241 Group *find_group(Object *ob, Group *group)
242 {
243         if (group)
244                 group = group->id.next;
245         else
246                 group = G.main->group.first;
247         
248         while (group) {
249                 if (object_in_group(ob, group))
250                         return group;
251                 group = group->id.next;
252         }
253         return NULL;
254 }
255
256 void group_tag_recalc(Group *group)
257 {
258         GroupObject *go;
259         
260         if (group == NULL) return;
261         
262         for (go = group->gobject.first; go; go = go->next) {
263                 if (go->ob) 
264                         go->ob->recalc = go->recalc;
265         }
266 }
267
268 int group_is_animated(Object *UNUSED(parent), Group *group)
269 {
270         GroupObject *go;
271
272 #if 0 /* XXX OLD ANIMSYS, NLASTRIPS ARE NO LONGER USED */
273         if (parent->nlastrips.first)
274                 return 1;
275 #endif
276
277         for (go = group->gobject.first; go; go = go->next)
278                 if (go->ob && go->ob->proxy)
279                         return 1;
280
281         return 0;
282 }
283
284 #if 0 // add back when timeoffset & animsys work again
285 /* only replaces object strips or action when parent nla instructs it */
286 /* keep checking nla.c though, in case internal structure of strip changes */
287 static void group_replaces_nla(Object *parent, Object *target, char mode)
288 {
289         static ListBase nlastrips = {NULL, NULL};
290         static bAction *action = NULL;
291         static int done = FALSE;
292         bActionStrip *strip, *nstrip;
293         
294         if (mode == 's') {
295                 
296                 for (strip = parent->nlastrips.first; strip; strip = strip->next) {
297                         if (strip->object == target) {
298                                 if (done == 0) {
299                                         /* clear nla & action from object */
300                                         nlastrips = target->nlastrips;
301                                         target->nlastrips.first = target->nlastrips.last = NULL;
302                                         action = target->action;
303                                         target->action = NULL;
304                                         target->nlaflag |= OB_NLA_OVERRIDE;
305                                         done = TRUE;
306                                 }
307                                 nstrip = MEM_dupallocN(strip);
308                                 BLI_addtail(&target->nlastrips, nstrip);
309                         }
310                 }
311         }
312         else if (mode == 'e') {
313                 if (done) {
314                         BLI_freelistN(&target->nlastrips);
315                         target->nlastrips = nlastrips;
316                         target->action = action;
317                         
318                         nlastrips.first = nlastrips.last = NULL;  /* not needed, but yah... :) */
319                         action = NULL;
320                         done = FALSE;
321                 }
322         }
323 }
324 #endif
325
326 /* puts all group members in local timing system, after this call
327  * you can draw everything, leaves tags in objects to signal it needs further updating */
328
329 /* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */
330 void group_handle_recalc_and_update(Scene *scene, Object *UNUSED(parent), Group *group)
331 {
332         GroupObject *go;
333         
334 #if 0 /* warning, isn't clearing the recalc flag on the object which causes it to run all the time,
335            * not just on frame change.
336            * This isn't working because the animation data is only re-evaluated on frame change so commenting for now
337            * but when its enabled at some point it will need to be changed so as not to update so much - campbell */
338
339         /* if animated group... */
340         if (parent->nlastrips.first) {
341                 int cfrao;
342                 
343                 /* switch to local time */
344                 cfrao = scene->r.cfra;
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                                 BKE_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                                         BKE_object_handle_update(scene, go->ob);
371                                 }
372                         }
373                 }
374         }
375 }