Render instancing can now also handle the same object in multiple,
[blender.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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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
33 #include "MEM_guardedalloc.h"
34
35 #include "DNA_action_types.h"
36 #include "DNA_effect_types.h"
37 #include "DNA_group_types.h"
38 #include "DNA_ID.h"
39 #include "DNA_ipo_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
45 #include "BLI_blenlib.h"
46
47 #include "BKE_global.h"
48 #include "BKE_group.h"
49 #include "BKE_ipo.h"
50 #include "BKE_library.h"
51 #include "BKE_main.h"
52 #include "BKE_object.h"
53
54 #ifdef HAVE_CONFIG_H
55 #include <config.h>
56 #endif
57
58 void free_group_object(GroupObject *go)
59 {
60         MEM_freeN(go);
61 }
62
63
64 void free_group(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         Material *ma;
79         Object *ob;
80         
81         for(ma= G.main->mat.first; ma; ma= ma->id.next) {
82                 if(ma->group==group)
83                         ma->group= NULL;
84         }
85         for(ob= G.main->object.first; ob; ob= ob->id.next) {
86                 bActionStrip *strip;
87                 PartEff *paf;
88                 
89                 if(ob->dup_group==group) {
90                         ob->dup_group= NULL;
91                 
92                         /* duplicator strips use a group object, we remove it */
93                         for(strip= ob->nlastrips.first; strip; strip= strip->next) {
94                                 if(strip->object)
95                                         strip->object= NULL;
96                         }
97                 }
98                 for(paf= ob->effect.first; paf; paf= paf->next) {
99                         if(paf->type==EFF_PARTICLE) {
100                                 if(paf->group)
101                                         paf->group= NULL;
102                         }
103                 }
104         }
105         group->id.us= 0;
106 }
107
108 Group *add_group(char *name)
109 {
110         Group *group;
111         
112         group = alloc_libblock(&G.main->group, ID_GR, name);
113         group->layer= (1<<20)-1;
114         return group;
115 }
116
117 /* external */
118 void add_to_group(Group *group, Object *ob)
119 {
120         GroupObject *go;
121         
122         if(group==NULL || ob==NULL) return;
123         
124         /* check if the object has been added already */
125         for(go= group->gobject.first; go; go= go->next) {
126                 if(go->ob==ob) return;
127         }
128         
129         go= MEM_callocN(sizeof(GroupObject), "groupobject");
130         BLI_addtail( &group->gobject, go);
131         
132         go->ob= ob;
133         
134 }
135
136 /* also used for ob==NULL */
137 void rem_from_group(Group *group, Object *ob)
138 {
139         GroupObject *go, *gon;
140         
141         if(group==NULL) return;
142         
143         go= group->gobject.first;
144         while(go) {
145                 gon= go->next;
146                 if(go->ob==ob) {
147                         BLI_remlink(&group->gobject, go);
148                         free_group_object(go);
149                 }
150                 go= gon;
151         }
152 }
153
154 int object_in_group(Object *ob, Group *group)
155 {
156         GroupObject *go;
157         
158         if(group==NULL || ob==NULL) return 0;
159         
160         for(go= group->gobject.first; go; go= go->next) {
161                 if(go->ob==ob) 
162                         return 1;
163         }
164         return 0;
165 }
166
167 Group *find_group(Object *ob, Group *group)
168 {
169         if (group)
170                 group= group->id.next;
171         else
172                 group= G.main->group.first;
173         
174         while(group) {
175                 if(object_in_group(ob, group))
176                         return group;
177                 group= group->id.next;
178         }
179         return NULL;
180 }
181
182 void group_tag_recalc(Group *group)
183 {
184         GroupObject *go;
185         
186         if(group==NULL) return;
187         
188         for(go= group->gobject.first; go; go= go->next) {
189                 if(go->ob) 
190                         go->ob->recalc= go->recalc;
191         }
192 }
193
194 int group_is_animated(Object *parent, Group *group)
195 {
196         GroupObject *go;
197
198         if(give_timeoffset(parent) != 0.0f || parent->nlastrips.first)
199                 return 1;
200
201         for(go= group->gobject.first; go; go= go->next)
202                 if(go->ob && go->ob->proxy)
203                         return 1;
204
205         return 0;
206 }
207
208 /* only replaces object strips or action when parent nla instructs it */
209 /* keep checking nla.c though, in case internal structure of strip changes */
210 static void group_replaces_nla(Object *parent, Object *target, char mode)
211 {
212         static ListBase nlastrips={NULL, NULL};
213         static bAction *action= NULL;
214         static int done= 0;
215         bActionStrip *strip, *nstrip;
216         
217         if(mode=='s') {
218                 
219                 for(strip= parent->nlastrips.first; strip; strip= strip->next) {
220                         if(strip->object==target) {
221                                 if(done==0) {
222                                         /* clear nla & action from object */
223                                         nlastrips= target->nlastrips;
224                                         target->nlastrips.first= target->nlastrips.last= NULL;
225                                         action= target->action;
226                                         target->action= NULL;
227                                         target->nlaflag |= OB_NLA_OVERRIDE;
228                                         done= 1;
229                                 }
230                                 nstrip= MEM_dupallocN(strip);
231                                 BLI_addtail(&target->nlastrips, nstrip);
232                         }
233                 }
234         }
235         else if(mode=='e') {
236                 if(done) {
237                         BLI_freelistN(&target->nlastrips);
238                         target->nlastrips= nlastrips;
239                         target->action= action;
240                         
241                         nlastrips.first= nlastrips.last= NULL;  /* not needed, but yah... :) */
242                         action= NULL;
243                         done= 0;
244                 }
245         }
246 }
247
248 /* puts all group members in local timing system, after this call
249 you can draw everything, leaves tags in objects to signal it needs further updating */
250
251 /* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */
252 void group_handle_recalc_and_update(Object *parent, Group *group)
253 {
254         GroupObject *go;
255         
256         /* if animated group... */
257         if(give_timeoffset(parent) != 0.0f || parent->nlastrips.first) {
258                 int cfrao;
259                 
260                 /* switch to local time */
261                 cfrao= G.scene->r.cfra;
262                 G.scene->r.cfra -= (int)give_timeoffset(parent);
263                 
264                 /* we need a DAG per group... */
265                 for(go= group->gobject.first; go; go= go->next) {
266                         if(go->ob && go->recalc) {
267                                 go->ob->recalc= go->recalc;
268                                 
269                                 group_replaces_nla(parent, go->ob, 's');
270                                 object_handle_update(go->ob);
271                                 group_replaces_nla(parent, go->ob, 'e');
272                                 
273                                 /* leave recalc tags in case group members are in normal scene */
274                                 go->ob->recalc= go->recalc;
275                         }
276                 }
277                 
278                 /* restore */
279                 G.scene->r.cfra= cfrao;
280         }
281         else {
282                 /* only do existing tags, as set by regular depsgraph */
283                 for(go= group->gobject.first; go; go= go->next) {
284                         if(go->ob) {
285                                 if(go->ob->recalc) {
286                                         object_handle_update(go->ob);
287                                 }
288                         }
289                 }
290         }
291 }
292
293 Object *group_get_member_with_action(Group *group, bAction *act)
294 {
295         GroupObject *go;
296         
297         if(group==NULL || act==NULL) return NULL;
298         
299         for(go= group->gobject.first; go; go= go->next) {
300                 if(go->ob) {
301                         if(go->ob->action==act)
302                                 return go->ob;
303                         if(go->ob->nlastrips.first) {
304                                 bActionStrip *strip;
305                                 
306                                 for(strip= go->ob->nlastrips.first; strip; strip= strip->next) {
307                                         if(strip->act==act)
308                                                 return go->ob;
309                                 }
310                         }
311                 }
312         }
313         return NULL;
314 }
315
316 /* if group has NLA, we try to map the used objects in NLA to group members */
317 /* this assuming that object has received a new group link */
318 void group_relink_nla_objects(Object *ob)
319 {
320         Group *group;
321         GroupObject *go;
322         bActionStrip *strip;
323         
324         if(ob==NULL || ob->dup_group==NULL) return;
325         group= ob->dup_group;
326         
327         for(strip= ob->nlastrips.first; strip; strip= strip->next) {
328                 if(strip->object) {
329                         for(go= group->gobject.first; go; go= go->next) {
330                                 if(go->ob) {
331                                         if(strcmp(go->ob->id.name, strip->object->id.name)==0)
332                                                 break;
333                                 }
334                         }
335                         if(go)
336                                 strip->object= go->ob;
337                         else
338                                 strip->object= NULL;
339                 }
340                         
341         }
342 }
343