Cleanup: Remove unused function
[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_scene_types.h"
43 #include "DNA_particle_types.h"
44
45 #include "BLI_blenlib.h"
46 #include "BLI_utildefines.h"
47
48
49 #include "BKE_depsgraph.h"
50 #include "BKE_global.h"
51 #include "BKE_group.h"
52 #include "BKE_icons.h"
53 #include "BKE_library.h"
54 #include "BKE_main.h"
55 #include "BKE_object.h"
56 #include "BKE_scene.h" /* BKE_scene_base_find */
57
58 static void free_group_object(GroupObject *go)
59 {
60         MEM_freeN(go);
61 }
62
63 /** Free (or release) any data used by this group (does not free the group itself). */
64 void BKE_group_free(Group *group)
65 {
66         /* don't free group itself */
67         GroupObject *go;
68
69         /* No animdata here. */
70
71         while ((go = BLI_pophead(&group->gobject))) {
72                 free_group_object(go);
73         }
74
75         BKE_previewimg_free(&group->preview);
76 }
77
78 Group *BKE_group_add(Main *bmain, const char *name)
79 {
80         Group *group;
81         
82         group = BKE_libblock_alloc(bmain, ID_GR, name, 0);
83         id_us_min(&group->id);
84         id_us_ensure_real(&group->id);
85         group->layer = (1 << 20) - 1;
86
87         group->preview = NULL;
88
89         return group;
90 }
91
92 /**
93  * Only copy internal data of Group ID from source to already allocated/initialized destination.
94  * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
95  *
96  * WARNING! This function will not handle ID user count!
97  *
98  * \param flag  Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
99  */
100 void BKE_group_copy_data(Main *UNUSED(bmain), Group *group_dst, const Group *group_src, const int flag)
101 {
102         BLI_duplicatelist(&group_dst->gobject, &group_src->gobject);
103
104         /* Do not copy group's preview (same behavior as for objects). */
105         if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) {  /* XXX TODO temp hack */
106                 BKE_previewimg_id_copy(&group_dst->id, &group_src->id);
107         }
108         else {
109                 group_dst->preview = NULL;
110         }
111 }
112
113 Group *BKE_group_copy(Main *bmain, const Group *group)
114 {
115         Group *group_copy;
116         BKE_id_copy_ex(bmain, &group->id, (ID **)&group_copy, 0, false);
117         return group_copy;
118 }
119
120 void BKE_group_make_local(Main *bmain, Group *group, const bool lib_local)
121 {
122         BKE_id_make_local_generic(bmain, &group->id, true, lib_local);
123 }
124
125 /* external */
126 static bool group_object_add_internal(Group *group, Object *ob)
127 {
128         GroupObject *go;
129         
130         if (group == NULL || ob == NULL) {
131                 return false;
132         }
133         
134         /* check if the object has been added already */
135         if (BLI_findptr(&group->gobject, ob, offsetof(GroupObject, ob))) {
136                 return false;
137         }
138         
139         go = MEM_callocN(sizeof(GroupObject), "groupobject");
140         BLI_addtail(&group->gobject, go);
141         
142         go->ob = ob;
143         id_us_ensure_real(&go->ob->id);
144         
145         return true;
146 }
147
148 bool BKE_group_object_add(Group *group, Object *object, Scene *scene, Base *base)
149 {
150         if (group_object_add_internal(group, object)) {
151                 if ((object->flag & OB_FROMGROUP) == 0) {
152
153                         if (scene && base == NULL)
154                                 base = BKE_scene_base_find(scene, object);
155
156                         object->flag |= OB_FROMGROUP;
157
158                         if (base)
159                                 base->flag |= OB_FROMGROUP;
160                 }
161                 return true;
162         }
163         else {
164                 return false;
165         }
166 }
167
168 /* also used for (ob == NULL) */
169 static int group_object_unlink_internal(Group *group, Object *ob)
170 {
171         GroupObject *go, *gon;
172         int removed = 0;
173         if (group == NULL) return 0;
174         
175         go = group->gobject.first;
176         while (go) {
177                 gon = go->next;
178                 if (go->ob == ob) {
179                         BLI_remlink(&group->gobject, go);
180                         free_group_object(go);
181                         removed = 1;
182                         /* should break here since an object being in a group twice cant happen? */
183                 }
184                 go = gon;
185         }
186         return removed;
187 }
188
189 static bool group_object_cyclic_check_internal(Object *object, Group *group)
190 {
191         if (object->dup_group) {
192                 Group *dup_group = object->dup_group;
193                 if ((dup_group->id.tag & LIB_TAG_DOIT) == 0) {
194                         /* Cycle already exists in groups, let's prevent further crappyness */
195                         return true;
196                 }
197                 /* flag the object to identify cyclic dependencies in further dupli groups */
198                 dup_group->id.tag &= ~LIB_TAG_DOIT;
199
200                 if (dup_group == group)
201                         return true;
202                 else {
203                         GroupObject *gob;
204                         for (gob = dup_group->gobject.first; gob; gob = gob->next) {
205                                 if (group_object_cyclic_check_internal(gob->ob, group)) {
206                                         return true;
207                                 }
208                         }
209                 }
210
211                 /* un-flag the object, it's allowed to have the same group multiple times in parallel */
212                 dup_group->id.tag |= LIB_TAG_DOIT;
213         }
214
215         return false;
216 }
217
218 bool BKE_group_object_cyclic_check(Main *bmain, Object *object, Group *group)
219 {
220         /* first flag all groups */
221         BKE_main_id_tag_listbase(&bmain->group, LIB_TAG_DOIT, true);
222
223         return group_object_cyclic_check_internal(object, group);
224 }
225
226 bool BKE_group_object_unlink(Group *group, Object *object, Scene *scene, Base *base)
227 {
228         if (group_object_unlink_internal(group, object)) {
229                 /* object can be NULL */
230                 if (object && BKE_group_object_find(NULL, object) == NULL) {
231                         if (scene && base == NULL)
232                                 base = BKE_scene_base_find(scene, object);
233
234                         object->flag &= ~OB_FROMGROUP;
235
236                         if (base)
237                                 base->flag &= ~OB_FROMGROUP;
238                 }
239                 return true;
240         }
241         else {
242                 return false;
243         }
244 }
245
246 bool BKE_group_object_exists(Group *group, Object *ob)
247 {
248         if (group == NULL || ob == NULL) {
249                 return false;
250         }
251         else {
252                 return (BLI_findptr(&group->gobject, ob, offsetof(GroupObject, ob)) != NULL);
253         }
254 }
255
256 Group *BKE_group_object_find(Group *group, Object *ob)
257 {
258         if (group)
259                 group = group->id.next;
260         else
261                 group = G.main->group.first;
262         
263         while (group) {
264                 if (BKE_group_object_exists(group, ob))
265                         return group;
266                 group = group->id.next;
267         }
268         return NULL;
269 }
270
271 bool BKE_group_is_animated(Group *group, Object *UNUSED(parent))
272 {
273         GroupObject *go;
274
275 #if 0 /* XXX OLD ANIMSYS, NLASTRIPS ARE NO LONGER USED */
276         if (parent->nlastrips.first)
277                 return 1;
278 #endif
279
280         for (go = group->gobject.first; go; go = go->next)
281                 if (go->ob && go->ob->proxy)
282                         return true;
283
284         return false;
285 }
286
287 #if 0 // add back when timeoffset & animsys work again
288 /* only replaces object strips or action when parent nla instructs it */
289 /* keep checking nla.c though, in case internal structure of strip changes */
290 static void group_replaces_nla(Object *parent, Object *target, char mode)
291 {
292         static ListBase nlastrips = {NULL, NULL};
293         static bAction *action = NULL;
294         static bool done = false;
295         bActionStrip *strip, *nstrip;
296         
297         if (mode == 's') {
298                 
299                 for (strip = parent->nlastrips.first; strip; strip = strip->next) {
300                         if (strip->object == target) {
301                                 if (done == 0) {
302                                         /* clear nla & action from object */
303                                         nlastrips = target->nlastrips;
304                                         BLI_listbase_clear(&target->nlastrips);
305                                         action = target->action;
306                                         target->action = NULL;
307                                         target->nlaflag |= OB_NLA_OVERRIDE;
308                                         done = true;
309                                 }
310                                 nstrip = MEM_dupallocN(strip);
311                                 BLI_addtail(&target->nlastrips, nstrip);
312                         }
313                 }
314         }
315         else if (mode == 'e') {
316                 if (done) {
317                         BLI_freelistN(&target->nlastrips);
318                         target->nlastrips = nlastrips;
319                         target->action = action;
320                         
321                         BLI_listbase_clear(&nlastrips);  /* not needed, but yah... :) */
322                         action = NULL;
323                         done = false;
324                 }
325         }
326 }
327 #endif
328
329 /* puts all group members in local timing system, after this call
330  * you can draw everything, leaves tags in objects to signal it needs further updating */
331
332 /* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */
333 void BKE_group_handle_recalc_and_update(EvaluationContext *eval_ctx, Scene *scene, Object *UNUSED(parent), Group *group)
334 {
335         GroupObject *go;
336         
337 #if 0 /* warning, isn't clearing the recalc flag on the object which causes it to run all the time,
338            * not just on frame change.
339            * This isn't working because the animation data is only re-evaluated on frame change so commenting for now
340            * but when its enabled at some point it will need to be changed so as not to update so much - campbell */
341
342         /* if animated group... */
343         if (parent->nlastrips.first) {
344                 int cfrao;
345                 
346                 /* switch to local time */
347                 cfrao = scene->r.cfra;
348                 
349                 /* we need a DAG per group... */
350                 for (go = group->gobject.first; go; go = go->next) {
351                         if (go->ob && go->recalc) {
352                                 go->ob->recalc = go->recalc;
353                                 
354                                 group_replaces_nla(parent, go->ob, 's');
355                                 BKE_object_handle_update(eval_ctx, scene, go->ob);
356                                 group_replaces_nla(parent, go->ob, 'e');
357                                 
358                                 /* leave recalc tags in case group members are in normal scene */
359                                 go->ob->recalc = go->recalc;
360                         }
361                 }
362                 
363                 /* restore */
364                 scene->r.cfra = cfrao;
365         }
366         else
367 #endif
368         {
369                 /* only do existing tags, as set by regular depsgraph */
370                 for (go = group->gobject.first; go; go = go->next) {
371                         if (go->ob) {
372                                 if (go->ob->recalc) {
373                                         BKE_object_handle_update(eval_ctx, scene, go->ob);
374                                 }
375                         }
376                 }
377         }
378 }