fix [#29616] Crash/infinite loop from missing cyclic check in group/dupligroups (unlikely/intentional)

calling BKE_ptcache_ids_from_object() could recursively call BKE_object_handle_update(), when there is no reason to update object transforms at all. Add option not to do any updates and just return an object list.
This commit is contained in:
Campbell Barton
2012-09-11 10:18:45 +00:00
parent 10d18e5b5f
commit 2cdfa33137
3 changed files with 48 additions and 22 deletions

View File

@@ -65,6 +65,7 @@ int where_on_path(struct Object *ob, float ctime, float vec[4], float dir[3], fl
/* ---------------------------------------------------- */ /* ---------------------------------------------------- */
/* Dupli-Geometry */ /* Dupli-Geometry */
struct ListBase *object_duplilist_ex(struct Scene *sce, struct Object *ob, int update);
struct ListBase *object_duplilist(struct Scene *sce, struct Object *ob); struct ListBase *object_duplilist(struct Scene *sce, struct Object *ob);
void free_object_duplilist(struct ListBase *lb); void free_object_duplilist(struct ListBase *lb);
int count_duplilist(struct Object *ob); int count_duplilist(struct Object *ob);

View File

@@ -74,7 +74,8 @@
/* --------------------- */ /* --------------------- */
/* forward declarations */ /* forward declarations */
static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[][4], int par_index, int level, int animated); static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[][4], int par_index,
int level, short animated, short update);
/* ******************************************************************** */ /* ******************************************************************** */
/* Animation Visualization */ /* Animation Visualization */
@@ -699,7 +700,7 @@ int where_on_path(Object *ob, float ctime, float vec[4], float dir[3], float qua
/* ******************************************************************** */ /* ******************************************************************** */
/* Dupli-Geometry */ /* Dupli-Geometry */
static DupliObject *new_dupli_object(ListBase *lb, Object *ob, float mat[][4], int lay, int index, int par_index, int type, int animated) static DupliObject *new_dupli_object(ListBase *lb, Object *ob, float mat[][4], int lay, int index, int par_index, int type, short animated)
{ {
DupliObject *dob = MEM_callocN(sizeof(DupliObject), "dupliobject"); DupliObject *dob = MEM_callocN(sizeof(DupliObject), "dupliobject");
@@ -717,7 +718,8 @@ static DupliObject *new_dupli_object(ListBase *lb, Object *ob, float mat[][4], i
return dob; return dob;
} }
static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int par_index, int level, int animated) static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int par_index,
int level, short animated, short update)
{ {
DupliObject *dob; DupliObject *dob;
Group *group; Group *group;
@@ -731,8 +733,14 @@ static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int par_inde
if (level > MAX_DUPLI_RECUR) return; if (level > MAX_DUPLI_RECUR) return;
/* handles animated groups, and */ /* handles animated groups, and */
/* we need to check update for objects that are not in scene... */ /* we need to check update for objects that are not in scene... */
group_handle_recalc_and_update(scene, ob, group); if (update) {
/* note: update is optional because we don't always need object
* transformations to be correct. Also fixes bug [#29616]. */
group_handle_recalc_and_update(scene, ob, group);
}
animated = animated || group_is_animated(ob, group); animated = animated || group_is_animated(ob, group);
for (go = group->gobject.first; go; go = go->next) { for (go = group->gobject.first; go; go = go->next) {
@@ -764,14 +772,14 @@ static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int par_inde
if (go->ob->transflag & OB_DUPLI) { if (go->ob->transflag & OB_DUPLI) {
copy_m4_m4(dob->ob->obmat, dob->mat); copy_m4_m4(dob->ob->obmat, dob->mat);
object_duplilist_recursive(&group->id, scene, go->ob, lb, ob->obmat, par_index, level + 1, animated); object_duplilist_recursive(&group->id, scene, go->ob, lb, ob->obmat, par_index, level + 1, animated, update);
copy_m4_m4(dob->ob->obmat, dob->omat); copy_m4_m4(dob->ob->obmat, dob->omat);
} }
} }
} }
} }
static void frames_duplilist(ListBase *lb, Scene *scene, Object *ob, int par_index, int level, int animated) static void frames_duplilist(ListBase *lb, Scene *scene, Object *ob, int par_index, int level, short animated)
{ {
extern int enable_cu_speed; /* object.c */ extern int enable_cu_speed; /* object.c */
Object copyob; Object copyob;
@@ -843,7 +851,8 @@ static void frames_duplilist(ListBase *lb, Scene *scene, Object *ob, int par_ind
typedef struct VertexDupliData { typedef struct VertexDupliData {
ID *id; /* scene or group, for recursive loops */ ID *id; /* scene or group, for recursive loops */
int level; int level;
int animated; short animated;
short update;
ListBase *lb; ListBase *lb;
float pmat[4][4]; float pmat[4][4];
float obmat[4][4]; /* Only used for dupliverts inside dupligroups, where the ob->obmat is modified */ float obmat[4][4]; /* Only used for dupliverts inside dupligroups, where the ob->obmat is modified */
@@ -899,12 +908,13 @@ static void vertex_dupli__mapFunc(void *userData, int index, const float co[3],
float tmpmat[4][4]; float tmpmat[4][4];
copy_m4_m4(tmpmat, vdd->ob->obmat); copy_m4_m4(tmpmat, vdd->ob->obmat);
copy_m4_m4(vdd->ob->obmat, obmat); /* pretend we are really this mat */ copy_m4_m4(vdd->ob->obmat, obmat); /* pretend we are really this mat */
object_duplilist_recursive((ID *)vdd->id, vdd->scene, vdd->ob, vdd->lb, obmat, vdd->par_index, vdd->level + 1, vdd->animated); object_duplilist_recursive((ID *)vdd->id, vdd->scene, vdd->ob, vdd->lb, obmat, vdd->par_index, vdd->level + 1, vdd->animated, vdd->update);
copy_m4_m4(vdd->ob->obmat, tmpmat); copy_m4_m4(vdd->ob->obmat, tmpmat);
} }
} }
static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int par_index, int level, int animated) static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int par_index,
int level, short animated, short update)
{ {
Object *ob, *ob_iter; Object *ob, *ob_iter;
Mesh *me = par->data; Mesh *me = par->data;
@@ -983,6 +993,7 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl
vdd.id = id; vdd.id = id;
vdd.level = level; vdd.level = level;
vdd.animated = animated; vdd.animated = animated;
vdd.update = update;
vdd.lb = lb; vdd.lb = lb;
vdd.ob = ob; vdd.ob = ob;
vdd.scene = scene; vdd.scene = scene;
@@ -1027,7 +1038,8 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl
dm->release(dm); dm->release(dm);
} }
static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int par_index, int level, int animated) static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int par_index,
int level, short animated, short update)
{ {
Object *ob, *ob_iter; Object *ob, *ob_iter;
Base *base = NULL; Base *base = NULL;
@@ -1197,7 +1209,7 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa
float tmpmat[4][4]; float tmpmat[4][4];
copy_m4_m4(tmpmat, ob->obmat); copy_m4_m4(tmpmat, ob->obmat);
copy_m4_m4(ob->obmat, obmat); /* pretend we are really this mat */ copy_m4_m4(ob->obmat, obmat); /* pretend we are really this mat */
object_duplilist_recursive((ID *)id, scene, ob, lb, ob->obmat, par_index, level + 1, animated); object_duplilist_recursive((ID *)id, scene, ob, lb, ob->obmat, par_index, level + 1, animated, update);
copy_m4_m4(ob->obmat, tmpmat); copy_m4_m4(ob->obmat, tmpmat);
} }
} }
@@ -1217,7 +1229,8 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa
dm->release(dm); dm->release(dm);
} }
static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int UNUSED(par_index), ParticleSystem *psys, int level, int animated) static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int UNUSED(par_index), ParticleSystem *psys,
int level, short animated, short update)
{ {
GroupObject *go; GroupObject *go;
Object *ob = NULL, **oblist = NULL, obcopy, *obcopylist = NULL; Object *ob = NULL, **oblist = NULL, obcopy, *obcopylist = NULL;
@@ -1300,7 +1313,9 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p
/* gather list of objects or single object */ /* gather list of objects or single object */
if (part->ren_as == PART_DRAW_GR) { if (part->ren_as == PART_DRAW_GR) {
group_handle_recalc_and_update(scene, par, part->dup_group); if (update) {
group_handle_recalc_and_update(scene, par, part->dup_group);
}
if (part->draw & PART_DRAW_COUNT_GR) { if (part->draw & PART_DRAW_COUNT_GR) {
for (dw = part->dupliweights.first; dw; dw = dw->next) for (dw = part->dupliweights.first; dw; dw = dw->next)
@@ -1555,7 +1570,7 @@ static Object *find_family_object(Object **obar, char *family, char ch)
} }
static void font_duplilist(ListBase *lb, Scene *scene, Object *par, int par_index, int level, int animated) static void font_duplilist(ListBase *lb, Scene *scene, Object *par, int par_index, int level, short animated)
{ {
Object *ob, *obar[256] = {NULL}; Object *ob, *obar[256] = {NULL};
Curve *cu; Curve *cu;
@@ -1603,7 +1618,8 @@ static void font_duplilist(ListBase *lb, Scene *scene, Object *par, int par_inde
/* ------------- */ /* ------------- */
static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[][4], int par_index, int level, int animated) static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[][4], int par_index,
int level, short animated, short update)
{ {
if ((ob->transflag & OB_DUPLI) == 0) if ((ob->transflag & OB_DUPLI) == 0)
return; return;
@@ -1623,11 +1639,11 @@ static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBas
if (ob->transflag & OB_DUPLIPARTS) { if (ob->transflag & OB_DUPLIPARTS) {
ParticleSystem *psys = ob->particlesystem.first; ParticleSystem *psys = ob->particlesystem.first;
for (; psys; psys = psys->next) for (; psys; psys = psys->next)
new_particle_duplilist(duplilist, id, scene, ob, par_space_mat, par_index, psys, level + 1, animated); new_particle_duplilist(duplilist, id, scene, ob, par_space_mat, par_index, psys, level + 1, animated, update);
} }
else if (ob->transflag & OB_DUPLIVERTS) { else if (ob->transflag & OB_DUPLIVERTS) {
if (ob->type == OB_MESH) { if (ob->type == OB_MESH) {
vertex_duplilist(duplilist, id, scene, ob, par_space_mat, par_index, level + 1, animated); vertex_duplilist(duplilist, id, scene, ob, par_space_mat, par_index, level + 1, animated, update);
} }
else if (ob->type == OB_FONT) { else if (ob->type == OB_FONT) {
if (GS(id->name) == ID_SCE) { /* TODO - support dupligroups */ if (GS(id->name) == ID_SCE) { /* TODO - support dupligroups */
@@ -1637,7 +1653,7 @@ static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBas
} }
else if (ob->transflag & OB_DUPLIFACES) { else if (ob->transflag & OB_DUPLIFACES) {
if (ob->type == OB_MESH) if (ob->type == OB_MESH)
face_duplilist(duplilist, id, scene, ob, par_space_mat, par_index, level + 1, animated); face_duplilist(duplilist, id, scene, ob, par_space_mat, par_index, level + 1, animated, update);
} }
else if (ob->transflag & OB_DUPLIFRAMES) { else if (ob->transflag & OB_DUPLIFRAMES) {
if (GS(id->name) == ID_SCE) { /* TODO - support dupligroups */ if (GS(id->name) == ID_SCE) { /* TODO - support dupligroups */
@@ -1647,7 +1663,7 @@ static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBas
else if (ob->transflag & OB_DUPLIGROUP) { else if (ob->transflag & OB_DUPLIGROUP) {
DupliObject *dob; DupliObject *dob;
group_duplilist(duplilist, scene, ob, par_index, level + 1, animated); /* now recursive */ group_duplilist(duplilist, scene, ob, par_index, level + 1, animated, update); /* now recursive */
if (level == 0) { if (level == 0) {
for (dob = duplilist->first; dob; dob = dob->next) for (dob = duplilist->first; dob; dob = dob->next)
@@ -1659,14 +1675,22 @@ static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBas
/* Returns a list of DupliObject /* Returns a list of DupliObject
* note; group dupli's already set transform matrix. see note in group_duplilist() */ * note; group dupli's already set transform matrix. see note in group_duplilist() */
ListBase *object_duplilist(Scene *sce, Object *ob) ListBase *object_duplilist_ex(Scene *sce, Object *ob, int update)
{ {
ListBase *duplilist = MEM_mallocN(sizeof(ListBase), "duplilist"); ListBase *duplilist = MEM_mallocN(sizeof(ListBase), "duplilist");
duplilist->first = duplilist->last = NULL; duplilist->first = duplilist->last = NULL;
object_duplilist_recursive((ID *)sce, sce, ob, duplilist, NULL, 0, 0, 0); object_duplilist_recursive((ID *)sce, sce, ob, duplilist, NULL, 0, 0, 0, update);
return duplilist; return duplilist;
} }
/* note: previously updating was always done, this is why it defaults to be on
* but there are likely places it can be called without updating */
ListBase *object_duplilist(Scene *sce, Object *ob)
{
return object_duplilist_ex(sce, ob, TRUE);
}
void free_object_duplilist(ListBase *lb) void free_object_duplilist(ListBase *lb)
{ {
DupliObject *dob; DupliObject *dob;

View File

@@ -1029,7 +1029,8 @@ void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int dup
if (scene && (duplis-- > 0) && (ob->transflag & OB_DUPLI)) { if (scene && (duplis-- > 0) && (ob->transflag & OB_DUPLI)) {
ListBase *lb_dupli_ob; ListBase *lb_dupli_ob;
if ((lb_dupli_ob=object_duplilist(scene, ob))) { /* don't update the dupli groups, we only wan't their pid's */
if ((lb_dupli_ob = object_duplilist_ex(scene, ob, FALSE))) {
DupliObject *dob; DupliObject *dob;
for (dob= lb_dupli_ob->first; dob; dob= dob->next) { for (dob= lb_dupli_ob->first; dob; dob= dob->next) {
if (dob->ob != ob) { /* avoids recursive loops with dupliframes: bug 22988 */ if (dob->ob != ob) { /* avoids recursive loops with dupliframes: bug 22988 */