Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/object_dupli.cc
| Show All 30 Lines | |||||
| #include "BLI_string_utf8.h" | #include "BLI_string_utf8.h" | ||||
| #include "BLI_array.hh" | #include "BLI_array.hh" | ||||
| #include "BLI_float3.hh" | #include "BLI_float3.hh" | ||||
| #include "BLI_float4x4.hh" | #include "BLI_float4x4.hh" | ||||
| #include "BLI_math.h" | #include "BLI_math.h" | ||||
| #include "BLI_rand.h" | #include "BLI_rand.h" | ||||
| #include "BLI_span.hh" | #include "BLI_span.hh" | ||||
| #include "BLI_vector.hh" | |||||
| #include "DNA_anim_types.h" | #include "DNA_anim_types.h" | ||||
| #include "DNA_collection_types.h" | #include "DNA_collection_types.h" | ||||
| #include "DNA_mesh_types.h" | #include "DNA_mesh_types.h" | ||||
| #include "DNA_meshdata_types.h" | #include "DNA_meshdata_types.h" | ||||
| #include "DNA_pointcloud_types.h" | #include "DNA_pointcloud_types.h" | ||||
| #include "DNA_scene_types.h" | #include "DNA_scene_types.h" | ||||
| #include "DNA_vfont_types.h" | #include "DNA_vfont_types.h" | ||||
| Show All 21 Lines | |||||
| #include "BLI_hash.h" | #include "BLI_hash.h" | ||||
| #include "BLI_strict_flags.h" | #include "BLI_strict_flags.h" | ||||
| using blender::Array; | using blender::Array; | ||||
| using blender::float3; | using blender::float3; | ||||
| using blender::float4x4; | using blender::float4x4; | ||||
| using blender::Span; | using blender::Span; | ||||
| using blender::Vector; | |||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Internal Duplicate Context | /** \name Internal Duplicate Context | ||||
| * \{ */ | * \{ */ | ||||
| struct DupliContext { | struct DupliContext { | ||||
| Depsgraph *depsgraph; | Depsgraph *depsgraph; | ||||
| /** XXX child objects are selected from this group if set, could be nicer. */ | /** XXX child objects are selected from this group if set, could be nicer. */ | ||||
| Collection *collection; | Collection *collection; | ||||
| /** Only to check if the object is in edit-mode. */ | /** Only to check if the object is in edit-mode. */ | ||||
| Object *obedit; | Object *obedit; | ||||
| Scene *scene; | Scene *scene; | ||||
| ViewLayer *view_layer; | ViewLayer *view_layer; | ||||
| Object *object; | Object *object; | ||||
| float space_mat[4][4]; | float space_mat[4][4]; | ||||
| /* Use a vector instead of a stack because we want to use the #contains method. */ | |||||
| Vector<Object *> *instance_stack; | |||||
HooglyBoogly: IMO there should be a brief comment about the purpose of the stack, it's not the most obvious… | |||||
| int persistent_id[MAX_DUPLI_RECUR]; | int persistent_id[MAX_DUPLI_RECUR]; | ||||
| int level; | int level; | ||||
| const struct DupliGenerator *gen; | const struct DupliGenerator *gen; | ||||
| /** Result containers. */ | /** Result containers. */ | ||||
| ListBase *duplilist; /* Legacy doubly-linked list. */ | ListBase *duplilist; /* Legacy doubly-linked list. */ | ||||
| }; | }; | ||||
| struct DupliGenerator { | struct DupliGenerator { | ||||
| short type; /* Dupli Type, see members of #OB_DUPLI. */ | short type; /* Dupli Type, see members of #OB_DUPLI. */ | ||||
| void (*make_duplis)(const DupliContext *ctx); | void (*make_duplis)(const DupliContext *ctx); | ||||
| }; | }; | ||||
| static const DupliGenerator *get_dupli_generator(const DupliContext *ctx); | static const DupliGenerator *get_dupli_generator(const DupliContext *ctx); | ||||
| /** | /** | ||||
| * Create initial context for root object. | * Create initial context for root object. | ||||
| */ | */ | ||||
| static void init_context(DupliContext *r_ctx, | static void init_context(DupliContext *r_ctx, | ||||
| Depsgraph *depsgraph, | Depsgraph *depsgraph, | ||||
| Scene *scene, | Scene *scene, | ||||
| Object *ob, | Object *ob, | ||||
| const float space_mat[4][4]) | const float space_mat[4][4], | ||||
| Vector<Object *> &instance_stack) | |||||
| { | { | ||||
| 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); | ||||
| r_ctx->collection = nullptr; | r_ctx->collection = nullptr; | ||||
| r_ctx->object = ob; | r_ctx->object = ob; | ||||
| r_ctx->obedit = OBEDIT_FROM_OBACT(ob); | r_ctx->obedit = OBEDIT_FROM_OBACT(ob); | ||||
| r_ctx->instance_stack = &instance_stack; | |||||
| 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; | ||||
| Show All 12 Lines | static void copy_dupli_context( | ||||
| /* XXX annoying, previously was done by passing an ID* argument, | /* XXX annoying, previously was done by passing an ID* argument, | ||||
| * this at least is more explicit. */ | * this at least is more explicit. */ | ||||
| if (ctx->gen->type == OB_DUPLICOLLECTION) { | if (ctx->gen->type == OB_DUPLICOLLECTION) { | ||||
| r_ctx->collection = ctx->object->instance_collection; | r_ctx->collection = ctx->object->instance_collection; | ||||
| } | } | ||||
| r_ctx->object = ob; | r_ctx->object = ob; | ||||
| r_ctx->instance_stack = ctx->instance_stack; | |||||
| 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 69 Lines • ▼ Show 20 Lines | |||||
| * | * | ||||
| * \param space_mat: is the local dupli-space (excluding dupli #Object.obmat). | * \param space_mat: is the local dupli-space (excluding dupli #Object.obmat). | ||||
| */ | */ | ||||
| static void make_recursive_duplis(const DupliContext *ctx, | static void make_recursive_duplis(const DupliContext *ctx, | ||||
| Object *ob, | Object *ob, | ||||
| const float space_mat[4][4], | const float space_mat[4][4], | ||||
| int index) | int index) | ||||
| { | { | ||||
| if (ctx->instance_stack->contains(ob)) { | |||||
| /* Avoid recursive instances. */ | |||||
| printf("Warning: '%s' object is trying to instance itself.\n", ob->id.name + 2); | |||||
| return; | |||||
| } | |||||
| /* Simple preventing of too deep nested collections 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); | copy_dupli_context(&rctx, ctx, ob, space_mat, index); | ||||
| if (rctx.gen) { | if (rctx.gen) { | ||||
| ctx->instance_stack->append(ob); | |||||
| rctx.gen->make_duplis(&rctx); | rctx.gen->make_duplis(&rctx); | ||||
| ctx->instance_stack->remove_last(); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Internal Child Duplicates (Used by Other Functions) | /** \name Internal Child Duplicates (Used by Other Functions) | ||||
| ▲ Show 20 Lines • Show All 1,331 Lines • ▼ Show 20 Lines | |||||
| /** | /** | ||||
| * \return a #ListBase of #DupliObject. | * \return a #ListBase of #DupliObject. | ||||
| */ | */ | ||||
| ListBase *object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob) | ListBase *object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob) | ||||
| { | { | ||||
| ListBase *duplilist = (ListBase *)MEM_callocN(sizeof(ListBase), "duplilist"); | ListBase *duplilist = (ListBase *)MEM_callocN(sizeof(ListBase), "duplilist"); | ||||
| DupliContext ctx; | DupliContext ctx; | ||||
| init_context(&ctx, depsgraph, sce, ob, nullptr); | Vector<Object *> instance_stack; | ||||
| instance_stack.append(ob); | |||||
| init_context(&ctx, depsgraph, sce, ob, nullptr, instance_stack); | |||||
| if (ctx.gen) { | if (ctx.gen) { | ||||
| ctx.duplilist = duplilist; | ctx.duplilist = duplilist; | ||||
| ctx.gen->make_duplis(&ctx); | ctx.gen->make_duplis(&ctx); | ||||
| } | } | ||||
| return duplilist; | return duplilist; | ||||
| } | } | ||||
| void free_object_duplilist(ListBase *lb) | void free_object_duplilist(ListBase *lb) | ||||
| { | { | ||||
| BLI_freelistN(lb); | BLI_freelistN(lb); | ||||
| MEM_freeN(lb); | MEM_freeN(lb); | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
IMO there should be a brief comment about the purpose of the stack, it's not the most obvious thing.