and RNA for it independent of the build flag for enabling Freestyle. Suggested by Sergey Sharybin through a code review of the branch. * Many #ifdef WITH_FREESTYLE blocks were removed to always have Freestyle-specific DNA file specification and RNA for it built in Blender. This will allow Freestyle setting survive even when a non-Freestyle build is used for loading and saving files. It is noted that operations are still conditionally built through #ifdef WITH_FREESTYLE blocks. * To this end, new blenkernel files BKE_freestyle.h and intern/freestyle.c have been added. All API functions in FRS_freestyle_config.h as well as some of those in FRS_freestyle.h were moved to the new files. Now the relocated API functions have BKE_ prefix instead of FRS_.
381 lines
8.8 KiB
C
381 lines
8.8 KiB
C
/*
|
|
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 *****
|
|
*/
|
|
|
|
/** \file blender/blenkernel/intern/group.c
|
|
* \ingroup bke
|
|
*/
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "DNA_group_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 "BLI_utildefines.h"
|
|
|
|
|
|
#include "BKE_global.h"
|
|
#include "BKE_group.h"
|
|
#include "BKE_library.h"
|
|
#include "BKE_main.h"
|
|
#include "BKE_object.h"
|
|
#include "BKE_scene.h" /* BKE_scene_base_find */
|
|
|
|
static void free_group_object(GroupObject *go)
|
|
{
|
|
MEM_freeN(go);
|
|
}
|
|
|
|
|
|
void BKE_group_free(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 BKE_group_unlink(Group *group)
|
|
{
|
|
Main *bmain = G.main;
|
|
Material *ma;
|
|
Object *ob;
|
|
Scene *sce;
|
|
SceneRenderLayer *srl;
|
|
FreestyleLineSet *lineset;
|
|
ParticleSystem *psys;
|
|
|
|
for (ma = bmain->mat.first; ma; ma = ma->id.next) {
|
|
if (ma->group == group)
|
|
ma->group = NULL;
|
|
}
|
|
for (ma = bmain->mat.first; ma; ma = ma->id.next) {
|
|
if (ma->group == group)
|
|
ma->group = NULL;
|
|
}
|
|
for (sce = bmain->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, sce, base) && 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(lineset = srl->freestyleConfig.linesets.first; lineset; lineset= lineset->next) {
|
|
if (lineset->group == group)
|
|
lineset->group = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (ob = bmain->object.first; ob; ob = ob->id.next) {
|
|
|
|
if (ob->dup_group == group) {
|
|
ob->dup_group = NULL;
|
|
}
|
|
|
|
for (psys = ob->particlesystem.first; psys; psys = psys->next) {
|
|
if (psys->part->dup_group == group)
|
|
psys->part->dup_group = NULL;
|
|
#if 0 /* not used anymore, only keps for readfile.c, no need to account for this */
|
|
if (psys->part->eff_group == group)
|
|
psys->part->eff_group = NULL;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* group stays in library, but no members */
|
|
BKE_group_free(group);
|
|
group->id.us = 0;
|
|
}
|
|
|
|
Group *add_group(Main *bmain, const char *name)
|
|
{
|
|
Group *group;
|
|
|
|
group = BKE_libblock_alloc(&bmain->group, ID_GR, name);
|
|
group->layer = (1 << 20) - 1;
|
|
return group;
|
|
}
|
|
|
|
Group *BKE_group_copy(Group *group)
|
|
{
|
|
Group *groupn;
|
|
|
|
groupn = MEM_dupallocN(group);
|
|
BLI_duplicatelist(&groupn->gobject, &group->gobject);
|
|
|
|
return groupn;
|
|
}
|
|
|
|
/* external */
|
|
static int add_to_group_internal(Group *group, Object *ob)
|
|
{
|
|
GroupObject *go;
|
|
|
|
if (group == NULL || ob == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
/* check if the object has been added already */
|
|
if (BLI_findptr(&group->gobject, ob, offsetof(GroupObject, ob))) {
|
|
return FALSE;
|
|
}
|
|
|
|
go = MEM_callocN(sizeof(GroupObject), "groupobject");
|
|
BLI_addtail(&group->gobject, go);
|
|
|
|
go->ob = ob;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
int add_to_group(Group *group, Object *object, Scene *scene, Base *base)
|
|
{
|
|
if (add_to_group_internal(group, object)) {
|
|
if ((object->flag & OB_FROMGROUP) == 0) {
|
|
|
|
if (scene && base == NULL)
|
|
base = BKE_scene_base_find(scene, object);
|
|
|
|
object->flag |= OB_FROMGROUP;
|
|
|
|
if (base)
|
|
base->flag |= OB_FROMGROUP;
|
|
}
|
|
return 1;
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* also used for (ob == NULL) */
|
|
static int rem_from_group_internal(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 rem_from_group(Group *group, Object *object, Scene *scene, Base *base)
|
|
{
|
|
if (rem_from_group_internal(group, object)) {
|
|
/* object can be NULL */
|
|
if (object && find_group(object, NULL) == NULL) {
|
|
if (scene && base == NULL)
|
|
base = BKE_scene_base_find(scene, object);
|
|
|
|
object->flag &= ~OB_FROMGROUP;
|
|
|
|
if (base)
|
|
base->flag &= ~OB_FROMGROUP;
|
|
}
|
|
return 1;
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int object_in_group(Object *ob, Group *group)
|
|
{
|
|
if (group == NULL || ob == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
return (BLI_findptr(&group->gobject, ob, offsetof(GroupObject, ob)) != NULL);
|
|
}
|
|
|
|
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 *UNUSED(parent), Group *group)
|
|
{
|
|
GroupObject *go;
|
|
|
|
#if 0 /* XXX OLD ANIMSYS, NLASTRIPS ARE NO LONGER USED */
|
|
if (parent->nlastrips.first)
|
|
return 1;
|
|
#endif
|
|
|
|
for (go = group->gobject.first; go; go = go->next)
|
|
if (go->ob && go->ob->proxy)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if 0 // add back when timeoffset & animsys work again
|
|
/* 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 = FALSE;
|
|
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 = TRUE;
|
|
}
|
|
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 = FALSE;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* 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 *UNUSED(parent), Group *group)
|
|
{
|
|
GroupObject *go;
|
|
|
|
#if 0 /* warning, isn't clearing the recalc flag on the object which causes it to run all the time,
|
|
* not just on frame change.
|
|
* This isn't working because the animation data is only re-evaluated on frame change so commenting for now
|
|
* but when its enabled at some point it will need to be changed so as not to update so much - campbell */
|
|
|
|
/* if animated group... */
|
|
if (parent->nlastrips.first) {
|
|
int cfrao;
|
|
|
|
/* switch to local time */
|
|
cfrao = scene->r.cfra;
|
|
|
|
/* 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');
|
|
BKE_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
|
|
#endif
|
|
{
|
|
/* 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) {
|
|
BKE_object_handle_update(scene, go->ob);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|