This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/blenkernel/intern/group.c

385 lines
8.4 KiB
C

/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
#include <stdio.h>
#include <string.h>
#include "MEM_guardedalloc.h"
#include "DNA_action_types.h"
#include "DNA_effect_types.h"
#include "DNA_group_types.h"
#include "DNA_ID.h"
#include "DNA_ipo_types.h"
#include "DNA_material_types.h"
#include "DNA_object_types.h"
#include "DNA_nla_types.h"
#include "DNA_scene_types.h"
#include "DNA_particle_types.h"
#include "BLI_blenlib.h"
#include "BKE_global.h"
#include "BKE_group.h"
#include "BKE_ipo.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_object.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
void free_group_object(GroupObject *go)
{
MEM_freeN(go);
}
void free_group(Group *group)
{
/* don't free group itself */
GroupObject *go;
while(group->gobject.first) {
go= group->gobject.first;
BLI_remlink(&group->gobject, go);
free_group_object(go);
}
}
void unlink_group(Group *group)
{
Material *ma;
Object *ob;
Scene *sce;
SceneRenderLayer *srl;
ParticleSystem *psys;
for(ma= G.main->mat.first; ma; ma= ma->id.next) {
if(ma->group==group)
ma->group= NULL;
}
for(ma= G.main->mat.first; ma; ma= ma->id.next) {
if(ma->group==group)
ma->group= NULL;
}
for (sce= G.main->scene.first; sce; sce= sce->id.next) {
Base *base= sce->base.first;
/* ensure objects are not in this group */
for(; base; base= base->next) {
if(rem_from_group(group, base->object) && find_group(base->object, NULL)==NULL) {
base->object->flag &= ~OB_FROMGROUP;
base->flag &= ~OB_FROMGROUP;
}
}
for(srl= sce->r.layers.first; srl; srl= srl->next) {
if (srl->light_override==group)
srl->light_override= NULL;
}
}
for(ob= G.main->object.first; ob; ob= ob->id.next) {
bActionStrip *strip;
if(ob->dup_group==group) {
ob->dup_group= NULL;
/* duplicator strips use a group object, we remove it */
for(strip= ob->nlastrips.first; strip; strip= strip->next) {
if(strip->object)
strip->object= NULL;
}
}
for(psys=ob->particlesystem.first; psys; psys=psys->next){
if(psys->part->dup_group==group)
psys->part->dup_group= NULL;
if(psys->part->eff_group==group)
psys->part->eff_group= NULL;
}
}
/* group stays in library, but no members */
free_group(group);
group->id.us= 0;
}
Group *add_group(char *name)
{
Group *group;
group = alloc_libblock(&G.main->group, ID_GR, name);
group->layer= (1<<20)-1;
return group;
}
Group *copy_group(Group *group)
{
Group *groupn;
groupn= MEM_dupallocN(group);
BLI_duplicatelist(&groupn->gobject, &group->gobject);
return groupn;
}
/* external */
void add_to_group(Group *group, Object *ob)
{
GroupObject *go;
if(group==NULL || ob==NULL) return;
/* check if the object has been added already */
for(go= group->gobject.first; go; go= go->next) {
if(go->ob==ob) return;
}
go= MEM_callocN(sizeof(GroupObject), "groupobject");
BLI_addtail( &group->gobject, go);
go->ob= ob;
}
/* also used for ob==NULL */
int rem_from_group(Group *group, Object *ob)
{
GroupObject *go, *gon;
int removed = 0;
if(group==NULL) return 0;
go= group->gobject.first;
while(go) {
gon= go->next;
if(go->ob==ob) {
BLI_remlink(&group->gobject, go);
free_group_object(go);
removed = 1;
/* should break here since an object being in a group twice cant happen? */
}
go= gon;
}
return removed;
}
int object_in_group(Object *ob, Group *group)
{
GroupObject *go;
if(group==NULL || ob==NULL) return 0;
for(go= group->gobject.first; go; go= go->next) {
if(go->ob==ob)
return 1;
}
return 0;
}
Group *find_group(Object *ob, Group *group)
{
if (group)
group= group->id.next;
else
group= G.main->group.first;
while(group) {
if(object_in_group(ob, group))
return group;
group= group->id.next;
}
return NULL;
}
void group_tag_recalc(Group *group)
{
GroupObject *go;
if(group==NULL) return;
for(go= group->gobject.first; go; go= go->next) {
if(go->ob)
go->ob->recalc= go->recalc;
}
}
int group_is_animated(Object *parent, Group *group)
{
GroupObject *go;
if(give_timeoffset(parent) != 0.0f || parent->nlastrips.first)
return 1;
for(go= group->gobject.first; go; go= go->next)
if(go->ob && go->ob->proxy)
return 1;
return 0;
}
/* only replaces object strips or action when parent nla instructs it */
/* keep checking nla.c though, in case internal structure of strip changes */
static void group_replaces_nla(Object *parent, Object *target, char mode)
{
static ListBase nlastrips={NULL, NULL};
static bAction *action= NULL;
static int done= 0;
bActionStrip *strip, *nstrip;
if(mode=='s') {
for(strip= parent->nlastrips.first; strip; strip= strip->next) {
if(strip->object==target) {
if(done==0) {
/* clear nla & action from object */
nlastrips= target->nlastrips;
target->nlastrips.first= target->nlastrips.last= NULL;
action= target->action;
target->action= NULL;
target->nlaflag |= OB_NLA_OVERRIDE;
done= 1;
}
nstrip= MEM_dupallocN(strip);
BLI_addtail(&target->nlastrips, nstrip);
}
}
}
else if(mode=='e') {
if(done) {
BLI_freelistN(&target->nlastrips);
target->nlastrips= nlastrips;
target->action= action;
nlastrips.first= nlastrips.last= NULL; /* not needed, but yah... :) */
action= NULL;
done= 0;
}
}
}
/* puts all group members in local timing system, after this call
you can draw everything, leaves tags in objects to signal it needs further updating */
/* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */
void group_handle_recalc_and_update(Scene *scene, Object *parent, Group *group)
{
GroupObject *go;
/* if animated group... */
if(give_timeoffset(parent) != 0.0f || parent->nlastrips.first) {
int cfrao;
/* switch to local time */
cfrao= scene->r.cfra;
scene->r.cfra -= (int)give_timeoffset(parent);
/* we need a DAG per group... */
for(go= group->gobject.first; go; go= go->next) {
if(go->ob && go->recalc) {
go->ob->recalc= go->recalc;
group_replaces_nla(parent, go->ob, 's');
object_handle_update(scene, go->ob);
group_replaces_nla(parent, go->ob, 'e');
/* leave recalc tags in case group members are in normal scene */
go->ob->recalc= go->recalc;
}
}
/* restore */
scene->r.cfra= cfrao;
}
else {
/* only do existing tags, as set by regular depsgraph */
for(go= group->gobject.first; go; go= go->next) {
if(go->ob) {
if(go->ob->recalc) {
object_handle_update(scene, go->ob);
}
}
}
}
}
Object *group_get_member_with_action(Group *group, bAction *act)
{
GroupObject *go;
if(group==NULL || act==NULL) return NULL;
for(go= group->gobject.first; go; go= go->next) {
if(go->ob) {
if(go->ob->action==act)
return go->ob;
if(go->ob->nlastrips.first) {
bActionStrip *strip;
for(strip= go->ob->nlastrips.first; strip; strip= strip->next) {
if(strip->act==act)
return go->ob;
}
}
}
}
return NULL;
}
/* if group has NLA, we try to map the used objects in NLA to group members */
/* this assuming that object has received a new group link */
void group_relink_nla_objects(Object *ob)
{
Group *group;
GroupObject *go;
bActionStrip *strip;
if(ob==NULL || ob->dup_group==NULL) return;
group= ob->dup_group;
for(strip= ob->nlastrips.first; strip; strip= strip->next) {
if(strip->object) {
for(go= group->gobject.first; go; go= go->next) {
if(go->ob) {
if(strcmp(go->ob->id.name, strip->object->id.name)==0)
break;
}
}
if(go)
strip->object= go->ob;
else
strip->object= NULL;
}
}
}