Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/object_dupli.cc
| Show First 20 Lines • Show All 141 Lines • ▼ Show 20 Lines | static void init_context(DupliContext *r_ctx, | ||||
| r_ctx->gen = get_dupli_generator(r_ctx); | r_ctx->gen = get_dupli_generator(r_ctx); | ||||
| r_ctx->duplilist = nullptr; | r_ctx->duplilist = nullptr; | ||||
| } | } | ||||
| /** | /** | ||||
| * Create sub-context for recursive duplis. | * Create sub-context for recursive duplis. | ||||
| */ | */ | ||||
| static void copy_dupli_context( | static bool copy_dupli_context( | ||||
| DupliContext *r_ctx, const DupliContext *ctx, Object *ob, const float mat[4][4], int index) | DupliContext *r_ctx, const DupliContext *ctx, Object *ob, const float mat[4][4], int index) | ||||
| { | { | ||||
| *r_ctx = *ctx; | *r_ctx = *ctx; | ||||
| /* 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; | 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; | ||||
| if (r_ctx->level == MAX_DUPLI_RECUR - 1) { | if (r_ctx->level == MAX_DUPLI_RECUR - 1) { | ||||
| std::cerr << "Warning: Maximum instance recursion level reached.\n"; | std::cerr << "Warning: Maximum instance recursion level reached.\n"; | ||||
| return false; | |||||
| } | } | ||||
| r_ctx->gen = get_dupli_generator(r_ctx); | r_ctx->gen = get_dupli_generator(r_ctx); | ||||
| return true; | |||||
| } | } | ||||
| /** | /** | ||||
| * Generate a dupli instance. | * Generate a dupli instance. | ||||
| * | * | ||||
| * \param mat: is transform of the object relative to current context (including #Object.obmat). | * \param mat: is transform of the object relative to current context (including #Object.obmat). | ||||
| */ | */ | ||||
| static DupliObject *make_dupli(const DupliContext *ctx, | static DupliObject *make_dupli(const DupliContext *ctx, | ||||
| ▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | static void make_recursive_duplis(const DupliContext *ctx, | ||||
| if (ctx->instance_stack->contains(ob)) { | if (ctx->instance_stack->contains(ob)) { | ||||
| /* Avoid recursive instances. */ | /* Avoid recursive instances. */ | ||||
| printf("Warning: '%s' object is trying to instance itself.\n", ob->id.name + 2); | printf("Warning: '%s' object is trying to instance itself.\n", ob->id.name + 2); | ||||
| return; | 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); | if (!copy_dupli_context(&rctx, ctx, ob, space_mat, index)) { | ||||
| return; | |||||
| } | |||||
| if (rctx.gen) { | if (rctx.gen) { | ||||
| ctx->instance_stack->append(ob); | ctx->instance_stack->append(ob); | ||||
| rctx.gen->make_duplis(&rctx); | rctx.gen->make_duplis(&rctx); | ||||
| ctx->instance_stack->remove_last(); | ctx->instance_stack->remove_last(); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| Show All 26 Lines | |||||
| { | { | ||||
| Object *parent = ctx->object; | Object *parent = ctx->object; | ||||
| if (ctx->collection) { | if (ctx->collection) { | ||||
| eEvaluationMode mode = DEG_get_mode(ctx->depsgraph); | eEvaluationMode mode = DEG_get_mode(ctx->depsgraph); | ||||
| FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (ctx->collection, ob, mode) { | FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (ctx->collection, ob, mode) { | ||||
| 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, nullptr, _base_id); | if (copy_dupli_context(&pctx, ctx, ctx->object, nullptr, _base_id)) { | ||||
| /* Meta-balls have a different dupli handling. */ | /* Meta-balls have a different dupli handling. */ | ||||
| if (ob->type != OB_MBALL) { | if (ob->type != OB_MBALL) { | ||||
| ob->flag |= OB_DONE; /* Doesn't render. */ | ob->flag |= OB_DONE; /* Doesn't render. */ | ||||
| } | } | ||||
| make_child_duplis_cb(&pctx, userdata, ob); | make_child_duplis_cb(&pctx, userdata, ob); | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; | FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; | ||||
| } | } | ||||
| else { | else { | ||||
| /* FIXME: using a mere counter to generate a 'persistent' dupli id is very weak. One possible | /* FIXME: using a mere counter to generate a 'persistent' dupli id is very weak. One possible | ||||
| * better solution could be to use `session_uuid` of ID's instead? */ | * better solution could be to use `session_uuid` of ID's instead? */ | ||||
| int persistent_dupli_id = 0; | int persistent_dupli_id = 0; | ||||
| /* NOTE: this set of flags ensure we only iterate over objects that have a base in either the | /* NOTE: this set of flags ensure we only iterate over objects that have a base in either the | ||||
| * current scene, or the set (background) scene. */ | * current scene, or the set (background) scene. */ | ||||
| int deg_objects_visibility_flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | | int deg_objects_visibility_flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | | ||||
| DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET; | DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET; | ||||
| DEG_OBJECT_ITER_BEGIN (ctx->depsgraph, ob, deg_objects_visibility_flags) { | DEG_OBJECT_ITER_BEGIN (ctx->depsgraph, ob, deg_objects_visibility_flags) { | ||||
| 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, nullptr, persistent_dupli_id); | if (copy_dupli_context(&pctx, ctx, ctx->object, nullptr, persistent_dupli_id)) { | ||||
| /* Meta-balls have a different dupli-handling. */ | /* Meta-balls have a different dupli-handling. */ | ||||
| if (ob->type != OB_MBALL) { | if (ob->type != OB_MBALL) { | ||||
| ob->flag |= OB_DONE; /* Doesn't render. */ | ob->flag |= OB_DONE; /* Doesn't render. */ | ||||
| } | } | ||||
| make_child_duplis_cb(&pctx, userdata, ob); | make_child_duplis_cb(&pctx, userdata, ob); | ||||
| } | } | ||||
| } | |||||
| persistent_dupli_id++; | persistent_dupli_id++; | ||||
| } | } | ||||
| DEG_OBJECT_ITER_END; | DEG_OBJECT_ITER_END; | ||||
| } | } | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| ▲ Show 20 Lines • Show All 544 Lines • ▼ Show 20 Lines | if (component == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| const DupliContext *instances_ctx = ctx; | const DupliContext *instances_ctx = ctx; | ||||
| /* Create a sub-context if some duplis were created above. This is to avoid dupli id collisions | /* Create a sub-context if some duplis were created above. This is to avoid dupli id collisions | ||||
| * between the instances component below and the other components above. */ | * between the instances component below and the other components above. */ | ||||
| DupliContext new_instances_ctx; | DupliContext new_instances_ctx; | ||||
| if (creates_duplis_for_components) { | if (creates_duplis_for_components) { | ||||
| copy_dupli_context(&new_instances_ctx, ctx, ctx->object, nullptr, component_index); | if (!copy_dupli_context(&new_instances_ctx, ctx, ctx->object, nullptr, component_index)) { | ||||
| return; | |||||
| } | |||||
| instances_ctx = &new_instances_ctx; | instances_ctx = &new_instances_ctx; | ||||
| } | } | ||||
| Span<float4x4> instance_offset_matrices = component->instance_transforms(); | Span<float4x4> instance_offset_matrices = component->instance_transforms(); | ||||
| Span<int> instance_reference_handles = component->instance_reference_handles(); | Span<int> instance_reference_handles = component->instance_reference_handles(); | ||||
| Span<int> almost_unique_ids = component->almost_unique_ids(); | Span<int> almost_unique_ids = component->almost_unique_ids(); | ||||
| Span<InstanceReference> references = component->references(); | Span<InstanceReference> references = component->references(); | ||||
| Show All 18 Lines | switch (reference.type()) { | ||||
| Collection &collection = reference.collection(); | Collection &collection = reference.collection(); | ||||
| float collection_matrix[4][4]; | float collection_matrix[4][4]; | ||||
| unit_m4(collection_matrix); | unit_m4(collection_matrix); | ||||
| sub_v3_v3(collection_matrix[3], collection.instance_offset); | sub_v3_v3(collection_matrix[3], collection.instance_offset); | ||||
| mul_m4_m4_pre(collection_matrix, instance_offset_matrices[i].values); | mul_m4_m4_pre(collection_matrix, instance_offset_matrices[i].values); | ||||
| mul_m4_m4_pre(collection_matrix, parent_transform); | mul_m4_m4_pre(collection_matrix, parent_transform); | ||||
| DupliContext sub_ctx; | DupliContext sub_ctx; | ||||
| copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id); | if (!copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id)) { | ||||
| break; | |||||
| } | |||||
| eEvaluationMode mode = DEG_get_mode(instances_ctx->depsgraph); | eEvaluationMode mode = DEG_get_mode(instances_ctx->depsgraph); | ||||
| int object_id = 0; | int object_id = 0; | ||||
| FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (&collection, object, mode) { | FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (&collection, object, mode) { | ||||
| if (object == instances_ctx->object) { | if (object == instances_ctx->object) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| float instance_matrix[4][4]; | float instance_matrix[4][4]; | ||||
| mul_m4_m4m4(instance_matrix, collection_matrix, object->obmat); | mul_m4_m4m4(instance_matrix, collection_matrix, object->obmat); | ||||
| make_dupli(&sub_ctx, object, instance_matrix, object_id++); | make_dupli(&sub_ctx, object, instance_matrix, object_id++); | ||||
| make_recursive_duplis(&sub_ctx, object, collection_matrix, object_id++); | make_recursive_duplis(&sub_ctx, object, collection_matrix, object_id++); | ||||
| } | } | ||||
| FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; | FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; | ||||
| break; | break; | ||||
| } | } | ||||
| case InstanceReference::Type::GeometrySet: { | case InstanceReference::Type::GeometrySet: { | ||||
| float new_transform[4][4]; | float new_transform[4][4]; | ||||
| mul_m4_m4m4(new_transform, parent_transform, instance_offset_matrices[i].values); | mul_m4_m4m4(new_transform, parent_transform, instance_offset_matrices[i].values); | ||||
| DupliContext sub_ctx; | DupliContext sub_ctx; | ||||
| copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id); | if (copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id)) { | ||||
| make_duplis_geometry_set_impl(&sub_ctx, reference.geometry_set(), new_transform, true); | make_duplis_geometry_set_impl(&sub_ctx, reference.geometry_set(), new_transform, true); | ||||
| } | |||||
| break; | break; | ||||
| } | } | ||||
| case InstanceReference::Type::None: { | case InstanceReference::Type::None: { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 640 Lines • ▼ Show 20 Lines | |||||
| static void make_duplis_particles(const DupliContext *ctx) | static void make_duplis_particles(const DupliContext *ctx) | ||||
| { | { | ||||
| /* Particle system take up one level in id, the particles another. */ | /* Particle system take up one level in id, the particles another. */ | ||||
| int psysid; | int psysid; | ||||
| LISTBASE_FOREACH_INDEX (ParticleSystem *, psys, &ctx->object->particlesystem, psysid) { | LISTBASE_FOREACH_INDEX (ParticleSystem *, psys, &ctx->object->particlesystem, psysid) { | ||||
| /* Particles create one more level for persistent `psys` index. */ | /* Particles create one more level for persistent `psys` index. */ | ||||
| DupliContext pctx; | DupliContext pctx; | ||||
| copy_dupli_context(&pctx, ctx, ctx->object, nullptr, psysid); | if (copy_dupli_context(&pctx, ctx, ctx->object, nullptr, psysid)) { | ||||
| make_duplis_particle_system(&pctx, psys); | make_duplis_particle_system(&pctx, psys); | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| static const DupliGenerator gen_dupli_particles = { | static const DupliGenerator gen_dupli_particles = { | ||||
| OB_DUPLIPARTS, /* type */ | OB_DUPLIPARTS, /* type */ | ||||
| make_duplis_particles /* make_duplis */ | make_duplis_particles /* make_duplis */ | ||||
| }; | }; | ||||
| /** \} */ | /** \} */ | ||||
| ▲ Show 20 Lines • Show All 79 Lines • Show Last 20 Lines | |||||