Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/object_dupli.c
| Show First 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | |||||
| #include "DNA_anim_types.h" | #include "DNA_anim_types.h" | ||||
| #include "DNA_group_types.h" | #include "DNA_group_types.h" | ||||
| #include "DNA_mesh_types.h" | #include "DNA_mesh_types.h" | ||||
| #include "DNA_scene_types.h" | #include "DNA_scene_types.h" | ||||
| #include "DNA_vfont_types.h" | #include "DNA_vfont_types.h" | ||||
| #include "BKE_animsys.h" | #include "BKE_animsys.h" | ||||
| #include "BKE_collection.h" | |||||
| #include "BKE_DerivedMesh.h" | #include "BKE_DerivedMesh.h" | ||||
| #include "BKE_font.h" | #include "BKE_font.h" | ||||
| #include "BKE_global.h" | #include "BKE_global.h" | ||||
| #include "BKE_group.h" | |||||
| #include "BKE_idprop.h" | #include "BKE_idprop.h" | ||||
| #include "BKE_lattice.h" | #include "BKE_lattice.h" | ||||
| #include "BKE_main.h" | #include "BKE_main.h" | ||||
| #include "BKE_mesh.h" | #include "BKE_mesh.h" | ||||
| #include "BKE_object.h" | #include "BKE_object.h" | ||||
| #include "BKE_particle.h" | #include "BKE_particle.h" | ||||
| #include "BKE_scene.h" | #include "BKE_scene.h" | ||||
| #include "BKE_editmesh.h" | #include "BKE_editmesh.h" | ||||
| #include "BKE_anim.h" | #include "BKE_anim.h" | ||||
| #include "DEG_depsgraph.h" | #include "DEG_depsgraph.h" | ||||
| #include "DEG_depsgraph_query.h" | #include "DEG_depsgraph_query.h" | ||||
| #include "BLI_strict_flags.h" | #include "BLI_strict_flags.h" | ||||
| #include "BLI_hash.h" | #include "BLI_hash.h" | ||||
| /* Dupli-Geometry */ | /* Dupli-Geometry */ | ||||
| typedef struct DupliContext { | typedef struct DupliContext { | ||||
| Depsgraph *depsgraph; | Depsgraph *depsgraph; | ||||
| bool do_update; | bool do_update; | ||||
| bool animated; | bool animated; | ||||
| Group *group; /* XXX child objects are selected from this group if set, could be nicer */ | Collection *collection; /* XXX child objects are selected from this group if set, could be nicer */ | ||||
| Object *obedit; /* Only to check if the object is in edit-mode. */ | Object *obedit; /* Only to check if the object is in edit-mode. */ | ||||
| Scene *scene; | Scene *scene; | ||||
| ViewLayer *view_layer; | ViewLayer *view_layer; | ||||
| Object *object; | Object *object; | ||||
| float space_mat[4][4]; | float space_mat[4][4]; | ||||
| int persistent_id[MAX_DUPLI_RECUR]; | int persistent_id[MAX_DUPLI_RECUR]; | ||||
| Show All 16 Lines | |||||
| static void init_context(DupliContext *r_ctx, Depsgraph *depsgraph, Scene *scene, Object *ob, float space_mat[4][4], bool update) | static void init_context(DupliContext *r_ctx, Depsgraph *depsgraph, Scene *scene, Object *ob, float space_mat[4][4], bool update) | ||||
| { | { | ||||
| r_ctx->depsgraph = depsgraph; | r_ctx->depsgraph = depsgraph; | ||||
| r_ctx->scene = scene; | r_ctx->scene = scene; | ||||
| r_ctx->view_layer = DEG_get_evaluated_view_layer(depsgraph); | r_ctx->view_layer = DEG_get_evaluated_view_layer(depsgraph); | ||||
| /* don't allow BKE_object_handle_update for viewport during render, can crash */ | /* don't allow BKE_object_handle_update for viewport during render, can crash */ | ||||
| r_ctx->do_update = update && !(G.is_rendering && DEG_get_mode(depsgraph) != DAG_EVAL_RENDER); | r_ctx->do_update = update && !(G.is_rendering && DEG_get_mode(depsgraph) != DAG_EVAL_RENDER); | ||||
| r_ctx->animated = false; | r_ctx->animated = false; | ||||
| r_ctx->group = NULL; | r_ctx->collection = NULL; | ||||
| r_ctx->object = ob; | r_ctx->object = ob; | ||||
| r_ctx->obedit = OBEDIT_FROM_OBACT(ob); | r_ctx->obedit = OBEDIT_FROM_OBACT(ob); | ||||
| if (space_mat) | if (space_mat) | ||||
| copy_m4_m4(r_ctx->space_mat, space_mat); | copy_m4_m4(r_ctx->space_mat, space_mat); | ||||
| else | else | ||||
| unit_m4(r_ctx->space_mat); | unit_m4(r_ctx->space_mat); | ||||
| r_ctx->level = 0; | r_ctx->level = 0; | ||||
| r_ctx->gen = get_dupli_generator(r_ctx); | r_ctx->gen = get_dupli_generator(r_ctx); | ||||
| r_ctx->duplilist = NULL; | r_ctx->duplilist = NULL; | ||||
| } | } | ||||
| /* create sub-context for recursive duplis */ | /* create sub-context for recursive duplis */ | ||||
| static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Object *ob, float mat[4][4], int index, bool animated) | static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Object *ob, float mat[4][4], int index, bool animated) | ||||
| { | { | ||||
| *r_ctx = *ctx; | *r_ctx = *ctx; | ||||
| r_ctx->animated |= animated; /* object animation makes all children animated */ | r_ctx->animated |= animated; /* object animation makes all children animated */ | ||||
| /* XXX annoying, previously was done by passing an ID* argument, this at least is more explicit */ | /* XXX annoying, previously was done by passing an ID* argument, this at least is more explicit */ | ||||
| if (ctx->gen->type == OB_DUPLIGROUP) | if (ctx->gen->type == OB_DUPLIGROUP) | ||||
| r_ctx->group = ctx->object->dup_group; | r_ctx->collection = ctx->object->dup_group; | ||||
| r_ctx->object = ob; | r_ctx->object = ob; | ||||
| if (mat) | if (mat) | ||||
| mul_m4_m4m4(r_ctx->space_mat, (float (*)[4])ctx->space_mat, mat); | mul_m4_m4m4(r_ctx->space_mat, (float (*)[4])ctx->space_mat, mat); | ||||
| r_ctx->persistent_id[r_ctx->level] = index; | r_ctx->persistent_id[r_ctx->level] = index; | ||||
| ++r_ctx->level; | ++r_ctx->level; | ||||
| r_ctx->gen = get_dupli_generator(r_ctx); | r_ctx->gen = get_dupli_generator(r_ctx); | ||||
| ▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | static DupliObject *make_dupli(const DupliContext *ctx, | ||||
| return dob; | return dob; | ||||
| } | } | ||||
| /* recursive dupli objects | /* recursive dupli objects | ||||
| * space_mat is the local dupli space (excluding dupli object obmat!) | * space_mat is the local dupli space (excluding dupli object obmat!) | ||||
| */ | */ | ||||
| static void make_recursive_duplis(const DupliContext *ctx, Object *ob, float space_mat[4][4], int index, bool animated) | static void make_recursive_duplis(const DupliContext *ctx, Object *ob, float space_mat[4][4], int index, bool animated) | ||||
| { | { | ||||
| /* simple preventing of too deep nested groups with MAX_DUPLI_RECUR */ | /* simple preventing of too deep nested collections with MAX_DUPLI_RECUR */ | ||||
| if (ctx->level < MAX_DUPLI_RECUR) { | if (ctx->level < MAX_DUPLI_RECUR) { | ||||
| DupliContext rctx; | DupliContext rctx; | ||||
| copy_dupli_context(&rctx, ctx, ob, space_mat, index, animated); | copy_dupli_context(&rctx, ctx, ob, space_mat, index, animated); | ||||
| if (rctx.gen) { | if (rctx.gen) { | ||||
| rctx.gen->make_duplis(&rctx); | rctx.gen->make_duplis(&rctx); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* ---- Child Duplis ---- */ | /* ---- Child Duplis ---- */ | ||||
| typedef void (*MakeChildDuplisFunc)(const DupliContext *ctx, void *userdata, Object *child); | typedef void (*MakeChildDuplisFunc)(const DupliContext *ctx, void *userdata, Object *child); | ||||
| static bool is_child(const Object *ob, const Object *parent) | static bool is_child(const Object *ob, const Object *parent) | ||||
| { | { | ||||
| const Object *ob_parent = ob->parent; | const Object *ob_parent = ob->parent; | ||||
| while (ob_parent) { | while (ob_parent) { | ||||
| if (ob_parent == parent) | if (ob_parent == parent) | ||||
| return true; | return true; | ||||
| ob_parent = ob_parent->parent; | ob_parent = ob_parent->parent; | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* create duplis from every child in scene or group */ | /* create duplis from every child in scene or collection */ | ||||
| static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChildDuplisFunc make_child_duplis_cb) | static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChildDuplisFunc make_child_duplis_cb) | ||||
| { | { | ||||
| Object *parent = ctx->object; | Object *parent = ctx->object; | ||||
| if (ctx->group) { | if (ctx->collection) { | ||||
| int groupid = 0; | int collectionid = 0; | ||||
| FOREACH_GROUP_BASE_BEGIN(ctx->group, base) | FOREACH_COLLECTION_BASE_RECURSIVE_BEGIN(ctx->collection, base) | ||||
| { | { | ||||
| Object *ob = base->object; | Object *ob = base->object; | ||||
| if ((base->flag & BASE_VISIBLED) && ob != ctx->obedit && is_child(ob, parent)) { | if ((base->flag & BASE_VISIBLED) && ob != ctx->obedit && is_child(ob, parent)) { | ||||
| DupliContext pctx; | DupliContext pctx; | ||||
| copy_dupli_context(&pctx, ctx, ctx->object, NULL, groupid, false); | copy_dupli_context(&pctx, ctx, ctx->object, NULL, collectionid, false); | ||||
| /* mballs have a different dupli handling */ | /* mballs have a different dupli handling */ | ||||
| if (ob->type != OB_MBALL) { | if (ob->type != OB_MBALL) { | ||||
| ob->flag |= OB_DONE; /* doesnt render */ | ob->flag |= OB_DONE; /* doesnt render */ | ||||
| } | } | ||||
| make_child_duplis_cb(&pctx, userdata, ob); | make_child_duplis_cb(&pctx, userdata, ob); | ||||
| } | } | ||||
| groupid++; | collectionid++; | ||||
| } | } | ||||
| FOREACH_GROUP_BASE_END | FOREACH_COLLECTION_BASE_RECURSIVE_END | ||||
| } | } | ||||
| else { | else { | ||||
| int baseid = 0; | int baseid = 0; | ||||
| ViewLayer *view_layer = ctx->view_layer; | ViewLayer *view_layer = ctx->view_layer; | ||||
| for (Base *base = view_layer->object_bases.first; base; base = base->next, baseid++) { | for (Base *base = view_layer->object_bases.first; base; base = base->next, baseid++) { | ||||
| Object *ob = base->object; | Object *ob = base->object; | ||||
| if ((ob != ctx->obedit) && is_child(ob, parent)) { | if ((ob != ctx->obedit) && is_child(ob, parent)) { | ||||
| DupliContext pctx; | DupliContext pctx; | ||||
| copy_dupli_context(&pctx, ctx, ctx->object, NULL, baseid, false); | copy_dupli_context(&pctx, ctx, ctx->object, NULL, baseid, false); | ||||
| /* mballs have a different dupli handling */ | /* mballs have a different dupli handling */ | ||||
| if (ob->type != OB_MBALL) | if (ob->type != OB_MBALL) | ||||
| ob->flag |= OB_DONE; /* doesnt render */ | ob->flag |= OB_DONE; /* doesnt render */ | ||||
| make_child_duplis_cb(&pctx, userdata, ob); | make_child_duplis_cb(&pctx, userdata, ob); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /*---- Implementations ----*/ | /*---- Implementations ----*/ | ||||
| /* OB_DUPLIGROUP */ | /* OB_DUPLIGROUP */ | ||||
| static void make_duplis_group(const DupliContext *ctx) | static void make_duplis_collection(const DupliContext *ctx) | ||||
| { | { | ||||
| Object *ob = ctx->object; | Object *ob = ctx->object; | ||||
| Group *group; | Collection *collection; | ||||
| Base *base; | Base *base; | ||||
| float group_mat[4][4]; | float collection_mat[4][4]; | ||||
| int id; | int id; | ||||
| bool animated; | bool animated; | ||||
| if (ob->dup_group == NULL) return; | if (ob->dup_group == NULL) return; | ||||
| group = ob->dup_group; | collection = ob->dup_group; | ||||
| /* combine group offset and obmat */ | /* combine collection offset and obmat */ | ||||
| unit_m4(group_mat); | unit_m4(collection_mat); | ||||
| sub_v3_v3(group_mat[3], group->dupli_ofs); | sub_v3_v3(collection_mat[3], collection->dupli_ofs); | ||||
| mul_m4_m4m4(group_mat, ob->obmat, group_mat); | mul_m4_m4m4(collection_mat, ob->obmat, collection_mat); | ||||
| /* don't access 'ob->obmat' from now on. */ | /* don't access 'ob->obmat' from now on. */ | ||||
| /* handles animated groups */ | /* handles animated collections */ | ||||
| /* we need to check update for objects that are not in scene... */ | /* we need to check update for objects that are not in scene... */ | ||||
| if (ctx->do_update) { | if (ctx->do_update) { | ||||
| /* note: update is optional because we don't always need object | /* note: update is optional because we don't always need object | ||||
| * transformations to be correct. Also fixes bug [#29616]. */ | * transformations to be correct. Also fixes bug [#29616]. */ | ||||
| BKE_group_handle_recalc_and_update(ctx->depsgraph, ctx->scene, ob, group); | BKE_collection_handle_recalc_and_update(ctx->depsgraph, ctx->scene, ob, collection); | ||||
| } | } | ||||
| animated = BKE_group_is_animated(group, ob); | animated = BKE_collection_is_animated(collection, ob); | ||||
| for (base = group->view_layer->object_bases.first, id = 0; base; base = base->next, id++) { | const ListBase dup_collection_objects = BKE_collection_object_cache_get(collection); | ||||
| for (base = dup_collection_objects.first, id = 0; base; base = base->next, id++) { | |||||
| if (base->object != ob && (base->flag & BASE_VISIBLED)) { | if (base->object != ob && (base->flag & BASE_VISIBLED)) { | ||||
| float mat[4][4]; | float mat[4][4]; | ||||
| /* group dupli offset, should apply after everything else */ | /* collection dupli offset, should apply after everything else */ | ||||
| mul_m4_m4m4(mat, group_mat, base->object->obmat); | mul_m4_m4m4(mat, collection_mat, base->object->obmat); | ||||
| make_dupli(ctx, base->object, mat, id, animated, false); | make_dupli(ctx, base->object, mat, id, animated, false); | ||||
| /* recursion */ | /* recursion */ | ||||
| make_recursive_duplis(ctx, base->object, group_mat, id, animated); | make_recursive_duplis(ctx, base->object, collection_mat, id, animated); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static const DupliGenerator gen_dupli_group = { | static const DupliGenerator gen_dupli_collection = { | ||||
| OB_DUPLIGROUP, /* type */ | OB_DUPLIGROUP, /* type */ | ||||
| make_duplis_group /* make_duplis */ | make_duplis_collection /* make_duplis */ | ||||
| }; | }; | ||||
| /* OB_DUPLIFRAMES */ | /* OB_DUPLIFRAMES */ | ||||
| static void make_duplis_frames(const DupliContext *ctx) | static void make_duplis_frames(const DupliContext *ctx) | ||||
| { | { | ||||
| Scene *scene = ctx->scene; | Scene *scene = ctx->scene; | ||||
| Object *ob = ctx->object; | Object *ob = ctx->object; | ||||
| extern int enable_cu_speed; /* object.c */ | extern int enable_cu_speed; /* object.c */ | ||||
| Object copyob; | Object copyob; | ||||
| int cfrao = scene->r.cfra; | int cfrao = scene->r.cfra; | ||||
| int dupend = ob->dupend; | int dupend = ob->dupend; | ||||
| /* dupliframes not supported inside groups */ | /* dupliframes not supported inside collections */ | ||||
| if (ctx->group) | if (ctx->collection) | ||||
| return; | return; | ||||
| /* if we don't have any data/settings which will lead to object movement, | /* if we don't have any data/settings which will lead to object movement, | ||||
| * don't waste time trying, as it will all look the same... | * don't waste time trying, as it will all look the same... | ||||
| */ | */ | ||||
| if (ob->parent == NULL && BLI_listbase_is_empty(&ob->constraints) && ob->adt == NULL) | if (ob->parent == NULL && BLI_listbase_is_empty(&ob->constraints) && ob->adt == NULL) | ||||
| return; | return; | ||||
| /* make a copy of the object's original data (before any dupli-data overwrites it) | /* make a copy of the object's original data (before any dupli-data overwrites it) | ||||
| ▲ Show 20 Lines • Show All 242 Lines • ▼ Show 20 Lines | static void make_duplis_font(const DupliContext *ctx) | ||||
| Curve *cu; | Curve *cu; | ||||
| struct CharTrans *ct, *chartransdata = NULL; | struct CharTrans *ct, *chartransdata = NULL; | ||||
| float vec[3], obmat[4][4], pmat[4][4], fsize, xof, yof; | float vec[3], obmat[4][4], pmat[4][4], fsize, xof, yof; | ||||
| int text_len, a; | int text_len, a; | ||||
| size_t family_len; | size_t family_len; | ||||
| const wchar_t *text = NULL; | const wchar_t *text = NULL; | ||||
| bool text_free = false; | bool text_free = false; | ||||
| /* font dupliverts not supported inside groups */ | /* font dupliverts not supported inside collections */ | ||||
| if (ctx->group) | if (ctx->collection) | ||||
| return; | return; | ||||
| copy_m4_m4(pmat, par->obmat); | copy_m4_m4(pmat, par->obmat); | ||||
| /* in par the family name is stored, use this to find the other objects */ | /* in par the family name is stored, use this to find the other objects */ | ||||
| BKE_vfont_to_curve_ex(G.main, par, par->data, FO_DUPLI, NULL, | BKE_vfont_to_curve_ex(G.main, par, par->data, FO_DUPLI, NULL, | ||||
| &text, &text_len, &text_free, &chartransdata); | &text, &text_len, &text_free, &chartransdata); | ||||
| ▲ Show 20 Lines • Show All 232 Lines • ▼ Show 20 Lines | static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem *psys) | ||||
| ParticleData *pa; | ParticleData *pa; | ||||
| ChildParticle *cpa = NULL; | ChildParticle *cpa = NULL; | ||||
| ParticleKey state; | ParticleKey state; | ||||
| ParticleCacheKey *cache; | ParticleCacheKey *cache; | ||||
| float ctime, pa_time, scale = 1.0f; | float ctime, pa_time, scale = 1.0f; | ||||
| float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size = 0.0; | float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size = 0.0; | ||||
| float (*obmat)[4]; | float (*obmat)[4]; | ||||
| int a, b, hair = 0; | int a, b, hair = 0; | ||||
| int totpart, totchild, totgroup = 0 /*, pa_num */; | int totpart, totchild, totcollection = 0 /*, pa_num */; | ||||
| int no_draw_flag = PARS_UNEXIST; | int no_draw_flag = PARS_UNEXIST; | ||||
| if (psys == NULL) return; | if (psys == NULL) return; | ||||
| part = psys->part; | part = psys->part; | ||||
| if (part == NULL) | if (part == NULL) | ||||
| Show All 23 Lines | if ((for_render || part->draw_as == PART_DRAW_REND) && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) { | ||||
| invert_m4_m4(par->imat, par->obmat); | invert_m4_m4(par->imat, par->obmat); | ||||
| /* first check for loops (particle system object used as dupli object) */ | /* first check for loops (particle system object used as dupli object) */ | ||||
| if (part->ren_as == PART_DRAW_OB) { | if (part->ren_as == PART_DRAW_OB) { | ||||
| if (ELEM(part->dup_ob, NULL, par)) | if (ELEM(part->dup_ob, NULL, par)) | ||||
| return; | return; | ||||
| } | } | ||||
| else { /*PART_DRAW_GR */ | else { /*PART_DRAW_GR */ | ||||
| if (part->dup_group == NULL || BLI_listbase_is_empty(&part->dup_group->view_layer->object_bases)) | if (part->dup_group == NULL) | ||||
| return; | return; | ||||
| if (BLI_findptr(&part->dup_group->view_layer->object_bases, par, offsetof(Base, object))) { | const ListBase dup_collection_objects = BKE_collection_object_cache_get(part->dup_group); | ||||
| if (BLI_listbase_is_empty(&dup_collection_objects)) | |||||
| return; | |||||
| if (BLI_findptr(&dup_collection_objects, par, offsetof(Base, object))) { | |||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| /* if we have a hair particle system, use the path cache */ | /* if we have a hair particle system, use the path cache */ | ||||
| if (part->type == PART_HAIR) { | if (part->type == PART_HAIR) { | ||||
| if (psys->flag & PSYS_HAIR_DONE) | if (psys->flag & PSYS_HAIR_DONE) | ||||
| hair = (totchild == 0 || psys->childcache) && psys->pathcache; | hair = (totchild == 0 || psys->childcache) && psys->pathcache; | ||||
| if (!hair) | if (!hair) | ||||
| return; | return; | ||||
| /* we use cache, update totchild according to cached data */ | /* we use cache, update totchild according to cached data */ | ||||
| totchild = psys->totchildcache; | totchild = psys->totchildcache; | ||||
| totpart = psys->totcached; | totpart = psys->totcached; | ||||
| } | } | ||||
| psys_check_group_weights(part); | psys_check_group_weights(part); | ||||
| psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); | psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); | ||||
| /* 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) { | ||||
| if (ctx->do_update) { | if (ctx->do_update) { | ||||
| BKE_group_handle_recalc_and_update(ctx->depsgraph, scene, par, part->dup_group); | BKE_collection_handle_recalc_and_update(ctx->depsgraph, 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) | ||||
| totgroup += dw->count; | totcollection += dw->count; | ||||
| } | } | ||||
| else { | else { | ||||
| FOREACH_GROUP_OBJECT_BEGIN(part->dup_group, object) | FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(part->dup_group, object) | ||||
| { | { | ||||
| (void) object; | (void) object; | ||||
| totgroup++; | totcollection++; | ||||
| } | } | ||||
| FOREACH_GROUP_OBJECT_END; | FOREACH_COLLECTION_OBJECT_RECURSIVE_END; | ||||
| } | } | ||||
| /* we also copy the actual objects to restore afterwards, since | /* we also copy the actual objects to restore afterwards, since | ||||
| * BKE_object_where_is_calc_time will change the object which breaks transform */ | * BKE_object_where_is_calc_time will change the object which breaks transform */ | ||||
| oblist = MEM_callocN((size_t)totgroup * sizeof(Object *), "dupgroup object list"); | oblist = MEM_callocN((size_t)totcollection * sizeof(Object *), "dupcollection object list"); | ||||
| obcopylist = MEM_callocN((size_t)totgroup * sizeof(Object), "dupgroup copy list"); | obcopylist = MEM_callocN((size_t)totcollection * sizeof(Object), "dupcollection copy list"); | ||||
| if (part->draw & PART_DRAW_COUNT_GR && totgroup) { | if (part->draw & PART_DRAW_COUNT_GR && totcollection) { | ||||
| dw = part->dupliweights.first; | dw = part->dupliweights.first; | ||||
| for (a = 0; a < totgroup; dw = dw->next) { | for (a = 0; a < totcollection; dw = dw->next) { | ||||
| for (b = 0; b < dw->count; b++, a++) { | for (b = 0; b < dw->count; b++, a++) { | ||||
| oblist[a] = dw->ob; | oblist[a] = dw->ob; | ||||
| obcopylist[a] = *dw->ob; | obcopylist[a] = *dw->ob; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| a = 0; | a = 0; | ||||
| FOREACH_GROUP_OBJECT_BEGIN(part->dup_group, object) | FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(part->dup_group, object) | ||||
| { | { | ||||
| oblist[a] = object; | oblist[a] = object; | ||||
| obcopylist[a] = *object; | obcopylist[a] = *object; | ||||
| a++; | a++; | ||||
| if (a >= totgroup) { | if (a >= totcollection) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| } | } | ||||
| FOREACH_GROUP_OBJECT_END; | FOREACH_COLLECTION_OBJECT_RECURSIVE_END; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| ob = part->dup_ob; | ob = part->dup_ob; | ||||
| obcopy = *ob; | obcopy = *ob; | ||||
| } | } | ||||
| if (totchild == 0 || part->draw & PART_DRAW_PARENT) | if (totchild == 0 || part->draw & PART_DRAW_PARENT) | ||||
| Show All 25 Lines | for (pa = psys->particles; a < totpart + totchild; a++, pa++) { | ||||
| ((a < totpart && psys->pathcache[a]->segments < 0) || | ((a < totpart && psys->pathcache[a]->segments < 0) || | ||||
| (a >= totpart && psys->childcache[a - totpart]->segments < 0))) | (a >= totpart && psys->childcache[a - totpart]->segments < 0))) | ||||
| { | { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (part->ren_as == PART_DRAW_GR) { | if (part->ren_as == PART_DRAW_GR) { | ||||
| /* prevent divide by zero below [#28336] */ | /* prevent divide by zero below [#28336] */ | ||||
| if (totgroup == 0) | if (totcollection == 0) | ||||
| continue; | continue; | ||||
| /* for groups, pick the object based on settings */ | /* for collections, pick the object based on settings */ | ||||
| if (part->draw & PART_DRAW_RAND_GR) | if (part->draw & PART_DRAW_RAND_GR) | ||||
| b = BLI_rand() % totgroup; | b = BLI_rand() % totcollection; | ||||
| else | else | ||||
| b = a % totgroup; | b = a % totcollection; | ||||
| ob = oblist[b]; | ob = oblist[b]; | ||||
| obmat = oblist[b]->obmat; | obmat = oblist[b]->obmat; | ||||
| } | } | ||||
| else { | else { | ||||
| obmat = ob->obmat; | obmat = ob->obmat; | ||||
| } | } | ||||
| Show All 24 Lines | for (pa = psys->particles; a < totpart + totchild; a++, pa++) { | ||||
| quat_to_mat4(pamat, tquat); | quat_to_mat4(pamat, tquat); | ||||
| copy_v3_v3(pamat[3], state.co); | copy_v3_v3(pamat[3], state.co); | ||||
| pamat[3][3] = 1.0f; | pamat[3][3] = 1.0f; | ||||
| } | } | ||||
| } | } | ||||
| if (part->ren_as == PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) { | if (part->ren_as == PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) { | ||||
| b = 0; | b = 0; | ||||
| FOREACH_GROUP_OBJECT_BEGIN(part->dup_group, object) | FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(part->dup_group, object) | ||||
| { | { | ||||
| copy_m4_m4(tmat, oblist[b]->obmat); | copy_m4_m4(tmat, oblist[b]->obmat); | ||||
| /* apply particle scale */ | /* apply particle scale */ | ||||
| mul_mat3_m4_fl(tmat, size * scale); | mul_mat3_m4_fl(tmat, size * scale); | ||||
| mul_v3_fl(tmat[3], size * scale); | mul_v3_fl(tmat[3], size * scale); | ||||
| /* group dupli offset, should apply after everything else */ | /* collection dupli offset, should apply after everything else */ | ||||
| if (!is_zero_v3(part->dup_group->dupli_ofs)) { | if (!is_zero_v3(part->dup_group->dupli_ofs)) { | ||||
| sub_v3_v3(tmat[3], part->dup_group->dupli_ofs); | sub_v3_v3(tmat[3], part->dup_group->dupli_ofs); | ||||
| } | } | ||||
| /* individual particle transform */ | /* individual particle transform */ | ||||
| mul_m4_m4m4(mat, pamat, tmat); | mul_m4_m4m4(mat, pamat, tmat); | ||||
| dob = make_dupli(ctx, object, mat, a, false, false); | dob = make_dupli(ctx, object, mat, a, false, false); | ||||
| dob->particle_system = psys; | dob->particle_system = psys; | ||||
| if (use_texcoords) { | if (use_texcoords) { | ||||
| psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); | psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); | ||||
| } | } | ||||
| b++; | b++; | ||||
| } | } | ||||
| FOREACH_GROUP_OBJECT_END; | FOREACH_COLLECTION_OBJECT_RECURSIVE_END; | ||||
| } | } | ||||
| else { | else { | ||||
| /* to give ipos in object correct offset */ | /* to give ipos in object correct offset */ | ||||
| BKE_object_where_is_calc_time(ctx->depsgraph, scene, ob, ctime - pa_time); | BKE_object_where_is_calc_time(ctx->depsgraph, scene, ob, ctime - pa_time); | ||||
| copy_v3_v3(vec, obmat[3]); | copy_v3_v3(vec, obmat[3]); | ||||
| obmat[3][0] = obmat[3][1] = obmat[3][2] = 0.0f; | obmat[3][0] = obmat[3][1] = obmat[3][2] = 0.0f; | ||||
| Show All 37 Lines | for (pa = psys->particles; a < totpart + totchild; a++, pa++) { | ||||
| dob->particle_system = psys; | dob->particle_system = psys; | ||||
| if (use_texcoords) | if (use_texcoords) | ||||
| psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); | psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); | ||||
| } | } | ||||
| } | } | ||||
| /* restore objects since they were changed in BKE_object_where_is_calc_time */ | /* restore objects since they were changed in BKE_object_where_is_calc_time */ | ||||
| if (part->ren_as == PART_DRAW_GR) { | if (part->ren_as == PART_DRAW_GR) { | ||||
| for (a = 0; a < totgroup; a++) | for (a = 0; a < totcollection; a++) | ||||
| *(oblist[a]) = obcopylist[a]; | *(oblist[a]) = obcopylist[a]; | ||||
| } | } | ||||
| else | else | ||||
| *ob = obcopy; | *ob = obcopy; | ||||
| } | } | ||||
| /* clean up */ | /* clean up */ | ||||
| if (oblist) | if (oblist) | ||||
| ▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | static const DupliGenerator *get_dupli_generator(const DupliContext *ctx) | ||||
| else if (transflag & OB_DUPLIFACES) { | else if (transflag & OB_DUPLIFACES) { | ||||
| if (ctx->object->type == OB_MESH) | if (ctx->object->type == OB_MESH) | ||||
| return &gen_dupli_faces; | return &gen_dupli_faces; | ||||
| } | } | ||||
| else if (transflag & OB_DUPLIFRAMES) { | else if (transflag & OB_DUPLIFRAMES) { | ||||
| return &gen_dupli_frames; | return &gen_dupli_frames; | ||||
| } | } | ||||
| else if (transflag & OB_DUPLIGROUP) { | else if (transflag & OB_DUPLIGROUP) { | ||||
| return &gen_dupli_group; | return &gen_dupli_collection; | ||||
| } | } | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| /* ---- ListBase dupli container implementation ---- */ | /* ---- ListBase dupli container implementation ---- */ | ||||
| ▲ Show 20 Lines • Show All 112 Lines • Show Last 20 Lines | |||||