diff --git a/source/blender/draw/engines/eevee/eevee_instance.hh b/source/blender/draw/engines/eevee/eevee_instance.hh index 435fe2c6d1f..54c79b058d1 100644 --- a/source/blender/draw/engines/eevee/eevee_instance.hh +++ b/source/blender/draw/engines/eevee/eevee_instance.hh @@ -338,23 +338,7 @@ class Instance : public DrawEngine { int get_recalc_flags(const ObjectRef &ob_ref) { - auto get_flags = [&](const ObjectRuntimeHandle &runtime) { - int flags = 0; - SET_FLAG_FROM_TEST( - flags, runtime.last_update_transform > depsgraph_last_update_, ID_RECALC_TRANSFORM); - SET_FLAG_FROM_TEST( - flags, runtime.last_update_geometry > depsgraph_last_update_, ID_RECALC_GEOMETRY); - SET_FLAG_FROM_TEST( - flags, runtime.last_update_shading > depsgraph_last_update_, ID_RECALC_SHADING); - return flags; - }; - - int flags = get_flags(*ob_ref.object->runtime); - if (ob_ref.dupli_parent) { - flags |= get_flags(*ob_ref.dupli_parent->runtime); - } - - return flags; + return ob_ref.recalc_flags(depsgraph_last_update_); } int get_recalc_flags(const ::World &world) diff --git a/source/blender/draw/engines/eevee/eevee_sync.hh b/source/blender/draw/engines/eevee/eevee_sync.hh index 72c0782bba1..22faa689300 100644 --- a/source/blender/draw/engines/eevee/eevee_sync.hh +++ b/source/blender/draw/engines/eevee/eevee_sync.hh @@ -24,86 +24,6 @@ namespace blender::eevee { class Instance; -/* -------------------------------------------------------------------- */ -/** \name ObjectKey - * - * Unique key to identify each object in the hash-map. - * Note that we get a unique key for each object component. - * \{ */ - -class ObjectKey { - /** Hash value of the key. */ - uint64_t hash_value_ = 0; - /** Original Object or source object for duplis. */ - Object *ob_ = nullptr; - /** Original Parent object for duplis. */ - Object *parent_ = nullptr; - /** Dupli objects recursive unique identifier */ - int id_[MAX_DUPLI_RECUR]; - /** Used for particle system hair. */ - int sub_key_ = 0; - - public: - ObjectKey() = default; - - ObjectKey(const ObjectRef &ob_ref, int sub_key = 0) - { - ob_ = DEG_get_original(ob_ref.object); - hash_value_ = get_default_hash(ob_); - - if (DupliObject *dupli = ob_ref.dupli_object) { - parent_ = ob_ref.dupli_parent; - hash_value_ = get_default_hash(hash_value_, get_default_hash(parent_)); - for (int i : IndexRange(MAX_DUPLI_RECUR)) { - id_[i] = dupli->persistent_id[i]; - if (id_[i] == INT_MAX) { - break; - } - hash_value_ = get_default_hash(hash_value_, get_default_hash(id_[i])); - } - } - - if (sub_key != 0) { - sub_key_ = sub_key; - hash_value_ = get_default_hash(hash_value_, get_default_hash(sub_key_)); - } - } - - uint64_t hash() const - { - return hash_value_; - } - - bool operator==(const ObjectKey &k) const - { - if (hash_value_ != k.hash_value_) { - return false; - } - if (ob_ != k.ob_) { - return false; - } - if (parent_ != k.parent_) { - return false; - } - if (sub_key_ != k.sub_key_) { - return false; - } - if (parent_) { - for (int i : IndexRange(MAX_DUPLI_RECUR)) { - if (id_[i] != k.id_[i]) { - return false; - } - if (id_[i] == INT_MAX) { - break; - } - } - } - return true; - } -}; - -/** \} */ - /* -------------------------------------------------------------------- */ /** \name Sync Module * diff --git a/source/blender/draw/engines/external/external_engine.cc b/source/blender/draw/engines/external/external_engine.cc index a0aacd2b331..a08f567e3a5 100644 --- a/source/blender/draw/engines/external/external_engine.cc +++ b/source/blender/draw/engines/external/external_engine.cc @@ -111,8 +111,7 @@ class Prepass { /* Case where the render engine should have rendered it, but we need to draw it for * selection purpose. */ if (handle.raw == 0u) { - handle = manager.resource_handle_for_psys(ob_ref, - DRW_particles_dupli_matrix_get(ob_ref)); + handle = manager.resource_handle_for_psys(ob_ref, ob_ref.particles_matrix()); } gpu::Batch *geom = DRW_cache_particles_get_hair(ob, psys, nullptr); diff --git a/source/blender/draw/engines/overlay/overlay_attribute_text.hh b/source/blender/draw/engines/overlay/overlay_attribute_text.hh index 5360b39018e..c2037799532 100644 --- a/source/blender/draw/engines/overlay/overlay_attribute_text.hh +++ b/source/blender/draw/engines/overlay/overlay_attribute_text.hh @@ -51,9 +51,7 @@ class AttributeTexts : Overlay { } const Object &object = *ob_ref.object; - const DupliObject *dupli_object = ob_ref.dupli_object; - const bool is_preview = dupli_object != nullptr && - dupli_object->preview_base_geometry != nullptr; + const bool is_preview = ob_ref.preview_base_geometry() != nullptr; if (!is_preview) { return; } @@ -61,11 +59,11 @@ class AttributeTexts : Overlay { DRWTextStore *dt = state.dt; const float4x4 &object_to_world = object.object_to_world(); - if (dupli_object->preview_instance_index >= 0) { - const bke::Instances *instances = dupli_object->preview_base_geometry->get_instances(); + if (ob_ref.preview_instance_index() >= 0) { + const bke::Instances *instances = ob_ref.preview_base_geometry()->get_instances(); if (instances->attributes().contains(".viewer")) { add_instance_attributes_to_text_cache( - dt, instances->attributes(), object_to_world, dupli_object->preview_instance_index); + dt, instances->attributes(), object_to_world, ob_ref.preview_instance_index()); return; } diff --git a/source/blender/draw/engines/overlay/overlay_attribute_viewer.hh b/source/blender/draw/engines/overlay/overlay_attribute_viewer.hh index cd42e69754a..c33ca014ef6 100644 --- a/source/blender/draw/engines/overlay/overlay_attribute_viewer.hh +++ b/source/blender/draw/engines/overlay/overlay_attribute_viewer.hh @@ -65,21 +65,19 @@ class AttributeViewer : Overlay { Resources & /*res*/, const State &state) final { - const DupliObject *dupli_object = ob_ref.dupli_object; - const bool is_preview = dupli_object != nullptr && - dupli_object->preview_base_geometry != nullptr; + const bool is_preview = ob_ref.preview_base_geometry() != nullptr; if (!enabled_ || !is_preview) { return; } - if (dupli_object->preview_instance_index >= 0) { + if (ob_ref.preview_instance_index() >= 0) { const auto &instances = - *dupli_object->preview_base_geometry->get_component(); + *ob_ref.preview_base_geometry()->get_component(); if (const std::optional meta_data = instances.attributes()->lookup_meta_data(".viewer")) { if (attribute_type_supports_viewer_overlay(meta_data->data_type)) { - populate_for_instance(ob_ref, *dupli_object, state, manager); + populate_for_instance(ob_ref, state, manager); return; } } @@ -107,13 +105,10 @@ class AttributeViewer : Overlay { } private: - void populate_for_instance(const ObjectRef &ob_ref, - const DupliObject &dupli_object, - const State &state, - Manager &manager) + void populate_for_instance(const ObjectRef &ob_ref, const State &state, Manager &manager) { Object &object = *ob_ref.object; - const bke::GeometrySet &base_geometry = *dupli_object.preview_base_geometry; + const bke::GeometrySet &base_geometry = *ob_ref.preview_base_geometry(); const bke::InstancesComponent &instances = *base_geometry.get_component(); const bke::AttributeAccessor instance_attributes = *instances.attributes(); @@ -121,7 +116,7 @@ class AttributeViewer : Overlay { if (!attribute) { return; } - ColorGeometry4f color = attribute.get(dupli_object.preview_instance_index); + ColorGeometry4f color = attribute.get(ob_ref.preview_instance_index()); color.a *= state.overlay.viewer_attribute_opacity; switch (object.type) { case OB_MESH: { diff --git a/source/blender/draw/engines/overlay/overlay_instance.cc b/source/blender/draw/engines/overlay/overlay_instance.cc index 05aae40207a..b1a15016c4c 100644 --- a/source/blender/draw/engines/overlay/overlay_instance.cc +++ b/source/blender/draw/engines/overlay/overlay_instance.cc @@ -975,9 +975,9 @@ bool Instance::object_is_sculpt_mode(const ObjectRef &ob_ref) const Object *active_object = state.object_active; const bool is_active_object = ob_ref.object == active_object; - bool is_geonode_preview = ob_ref.dupli_object && ob_ref.dupli_object->preview_base_geometry; - bool is_active_dupli_parent = ob_ref.dupli_parent == active_object; - return is_active_object || (is_active_dupli_parent && is_geonode_preview); + bool is_active_geonode_preview = ob_ref.preview_base_geometry() != nullptr && + ob_ref.is_active(state.object_active); + return is_active_object || is_active_geonode_preview; } if (state.object_mode == OB_MODE_SCULPT) { @@ -1008,13 +1008,9 @@ bool Instance::object_is_edit_paint_mode(const ObjectRef &ob_ref, bool in_sculpt_mode) { bool in_edit_paint_mode = in_edit_mode || in_paint_mode || in_sculpt_mode; - if (ob_ref.object->base_flag & BASE_FROM_DUPLI) { - /* Disable outlines for objects instanced by an object in sculpt, paint or edit mode. */ - in_edit_paint_mode |= ob_ref.dupli_parent && (object_is_edit_mode(ob_ref.dupli_parent) || - object_is_sculpt_mode(ob_ref.dupli_parent) || - object_is_paint_mode(ob_ref.dupli_parent)); - } - return in_edit_paint_mode; + /* Disable outlines for objects instanced by an object in sculpt, paint or edit mode. */ + return in_edit_paint_mode || ob_ref.parent_is_in_edit_paint_mode( + state.object_active, state.object_mode, state.ctx_mode); } bool Instance::object_is_edit_mode(const Object *object) diff --git a/source/blender/draw/engines/overlay/overlay_particle.hh b/source/blender/draw/engines/overlay/overlay_particle.hh index 0d061cd0ca9..03e15af1ff9 100644 --- a/source/blender/draw/engines/overlay/overlay_particle.hh +++ b/source/blender/draw/engines/overlay/overlay_particle.hh @@ -163,8 +163,7 @@ class Particles : Overlay { Object *ob = ob_ref.object; - ResourceHandle handle = manager.resource_handle_for_psys( - ob_ref, DRW_particles_dupli_matrix_get(ob_ref)); + ResourceHandle handle = manager.resource_handle_for_psys(ob_ref, ob_ref.particles_matrix()); { gpu::Batch *geom = DRW_cache_particles_get_edit_strands(ob, psys, edit, show_weight_); @@ -199,7 +198,7 @@ class Particles : Overlay { } if (handle.raw == 0u) { - handle = manager.resource_handle_for_psys(ob_ref, DRW_particles_dupli_matrix_get(ob_ref)); + handle = manager.resource_handle_for_psys(ob_ref, ob_ref.particles_matrix()); } const ParticleSettings *part = psys->part; diff --git a/source/blender/draw/engines/overlay/overlay_prepass.hh b/source/blender/draw/engines/overlay/overlay_prepass.hh index dd205883f97..9af36ffdc68 100644 --- a/source/blender/draw/engines/overlay/overlay_prepass.hh +++ b/source/blender/draw/engines/overlay/overlay_prepass.hh @@ -147,8 +147,7 @@ class Prepass : Overlay { /* Case where the render engine should have rendered it, but we need to draw it for * selection purpose. */ if (handle.raw == 0u) { - handle = manager.resource_handle_for_psys(ob_ref, - DRW_particles_dupli_matrix_get(ob_ref)); + handle = manager.resource_handle_for_psys(ob_ref, ob_ref.particles_matrix()); } select::ID select_id = use_material_slot_selection_ ? diff --git a/source/blender/draw/engines/overlay/overlay_private.hh b/source/blender/draw/engines/overlay/overlay_private.hh index 5210231f140..384e3ed82e3 100644 --- a/source/blender/draw/engines/overlay/overlay_private.hh +++ b/source/blender/draw/engines/overlay/overlay_private.hh @@ -898,9 +898,7 @@ struct Resources : public select::SelectMap { { const bool is_edit = (state.object_mode & OB_MODE_EDIT) && (ob_ref.object->mode & OB_MODE_EDIT); - const bool active = ((ob_ref.dupli_parent != nullptr) ? - (state.object_active == ob_ref.dupli_parent) : - (state.object_active == ob_ref.object)); + const bool active = ob_ref.is_active(state.object_active); const bool is_selected = ((ob_ref.object->base_flag & BASE_SELECTED) != 0); /* Object in edit mode. */ diff --git a/source/blender/draw/intern/draw_cache_impl.hh b/source/blender/draw/intern/draw_cache_impl.hh index 4d2349d44e2..8029b415ae4 100644 --- a/source/blender/draw/intern/draw_cache_impl.hh +++ b/source/blender/draw/intern/draw_cache_impl.hh @@ -328,10 +328,6 @@ blender::gpu::Batch *DRW_particles_batch_cache_get_edit_tip_points(Object *objec ParticleSystem *psys, PTCacheEdit *edit); -/* Particle data are stored in world space. If an object is instanced, the associated particle - * systems need to be offset appropriately. */ -float4x4 DRW_particles_dupli_matrix_get(const ObjectRef &ob_ref); - /** \} */ } // namespace blender::draw diff --git a/source/blender/draw/intern/draw_cache_impl_particles.cc b/source/blender/draw/intern/draw_cache_impl_particles.cc index ccaa7c83ffc..5b18dfd4d76 100644 --- a/source/blender/draw/intern/draw_cache_impl_particles.cc +++ b/source/blender/draw/intern/draw_cache_impl_particles.cc @@ -1703,26 +1703,6 @@ gpu::Batch *DRW_particles_batch_cache_get_edit_tip_points(Object *object, return cache->edit_tip_points; } -float4x4 DRW_particles_dupli_matrix_get(const ObjectRef &ob_ref) -{ - float4x4 dupli_mat = float4x4::identity(); - - if ((ob_ref.dupli_parent != nullptr) && (ob_ref.dupli_object != nullptr)) { - if (ob_ref.dupli_object->type & OB_DUPLICOLLECTION) { - Collection *collection = ob_ref.dupli_parent->instance_collection; - if (collection != nullptr) { - dupli_mat[3] -= float4(float3(collection->instance_offset), 0.0f); - } - dupli_mat = ob_ref.dupli_parent->object_to_world() * dupli_mat; - } - else { - dupli_mat = ob_ref.object->object_to_world() * - math::invert(ob_ref.dupli_object->ob->object_to_world()); - } - } - return dupli_mat; -} - bool particles_ensure_procedural_data(Object *object, ParticleSystem *psys, ModifierData *md, diff --git a/source/blender/draw/intern/draw_common_c.hh b/source/blender/draw/intern/draw_common_c.hh index 133066f0865..f0512b310e0 100644 --- a/source/blender/draw/intern/draw_common_c.hh +++ b/source/blender/draw/intern/draw_common_c.hh @@ -39,10 +39,6 @@ struct ObjectRef; blender::gpu::VertBuf *DRW_hair_pos_buffer_get(Object *object, ParticleSystem *psys, ModifierData *md); -void DRW_hair_duplimat_get(const blender::draw::ObjectRef &ob_ref, - ParticleSystem *psys, - ModifierData *md, - float (*dupli_mat)[4]); /* draw_curves.cc */ diff --git a/source/blender/draw/intern/draw_context.cc b/source/blender/draw/intern/draw_context.cc index 9f0016f00ec..30f1fa8bfde 100644 --- a/source/blender/draw/intern/draw_context.cc +++ b/source/blender/draw/intern/draw_context.cc @@ -600,13 +600,13 @@ void DupliCacheManager::try_add(blender::draw::ObjectRef &ob_ref) if (ob_ref.is_dupli() == false) { return; } - if (last_key_ == ob_ref.dupli_object) { + if (last_key_ == ob_ref.dupli_object_) { /* Same data as previous iteration. No need to perform the check again. */ return; } - last_key_.ob = ob_ref.dupli_object->ob; - last_key_.ob_data = ob_ref.dupli_object->ob_data; + last_key_.ob = ob_ref.dupli_object_->ob; + last_key_.ob_data = ob_ref.dupli_object_->ob_data; if (dupli_set_ == nullptr) { dupli_set_ = MEM_new>("DupliCacheManager::dupli_set_"); @@ -675,8 +675,8 @@ namespace blender::draw { ObjectRef::ObjectRef(DEGObjectIterData &iter_data, Object *ob) { - this->dupli_parent = iter_data.dupli_parent; - this->dupli_object = iter_data.dupli_object_current; + this->dupli_parent_ = iter_data.dupli_parent; + this->dupli_object_ = iter_data.dupli_object_current; this->object = ob; /* Set by the first draw-call. */ this->handle = ResourceHandle(0); @@ -684,8 +684,8 @@ ObjectRef::ObjectRef(DEGObjectIterData &iter_data, Object *ob) ObjectRef::ObjectRef(Object *ob) { - this->dupli_parent = nullptr; - this->dupli_object = nullptr; + this->dupli_parent_ = nullptr; + this->dupli_object_ = nullptr; this->object = ob; /* Set by the first draw-call. */ this->handle = ResourceHandle(0); diff --git a/source/blender/draw/intern/draw_hair.cc b/source/blender/draw/intern/draw_hair.cc index 6a4ae8f3e87..fb99de3d90c 100644 --- a/source/blender/draw/intern/draw_hair.cc +++ b/source/blender/draw/intern/draw_hair.cc @@ -98,34 +98,6 @@ blender::gpu::VertBuf *DRW_hair_pos_buffer_get(Object *object, return cache->final[subdiv].proc_buf; } -void DRW_hair_duplimat_get(const blender::draw::ObjectRef &ob_ref, - ParticleSystem * /*psys*/, - ModifierData * /*md*/, - float (*dupli_mat)[4]) -{ - Object *dupli_parent = ob_ref.dupli_parent; - DupliObject *dupli_object = ob_ref.dupli_object; - - if ((dupli_parent != nullptr) && (dupli_object != nullptr)) { - if (dupli_object->type & OB_DUPLICOLLECTION) { - unit_m4(dupli_mat); - Collection *collection = dupli_parent->instance_collection; - if (collection != nullptr) { - sub_v3_v3(dupli_mat[3], collection->instance_offset); - } - mul_m4_m4m4(dupli_mat, dupli_parent->object_to_world().ptr(), dupli_mat); - } - else { - copy_m4_m4(dupli_mat, dupli_object->ob->object_to_world().ptr()); - invert_m4(dupli_mat); - mul_m4_m4m4(dupli_mat, ob_ref.object->object_to_world().ptr(), dupli_mat); - } - } - else { - unit_m4(dupli_mat); - } -} - /* New Draw Manager. */ #include "draw_common.hh" @@ -233,8 +205,7 @@ blender::gpu::Batch *hair_sub_pass_setup_implementation(PassT &sub_ps, sub_ps.bind_texture("ac", module.dummy_vbo); } - float4x4 dupli_mat; - DRW_hair_duplimat_get(ob_ref, psys, md, dupli_mat.ptr()); + float4x4 dupli_mat = ob_ref.particles_matrix(); /* Get hair shape parameters. */ ParticleSettings *part = psys->part; diff --git a/source/blender/draw/intern/draw_handle.hh b/source/blender/draw/intern/draw_handle.hh index ff6bb3f9587..fa232960c44 100644 --- a/source/blender/draw/intern/draw_handle.hh +++ b/source/blender/draw/intern/draw_handle.hh @@ -19,11 +19,29 @@ * the origin. */ +#include "BKE_duplilist.hh" #include "draw_shader_shared.hh" -struct Object; -struct DupliObject; -struct DEGObjectIterData; +/* random */ +#include "BLI_hash.h" + +/* find_rgba_attribute */ +#include "GPU_material.hh" + +/* particles_matrix */ +#include "BLI_math_matrix.hh" +#include "DNA_collection_types.h" + +/* parent_is_in_edit_paint_mode */ +#include "BKE_context.hh" +#include "BKE_paint.hh" +#include "DNA_layer_types.h" +#include "DRW_render.hh" + +/* ObjectKey */ +#include "DEG_depsgraph_query.hh" + +struct DupliCacheManager; namespace blender::draw { @@ -79,11 +97,17 @@ struct ResourceHandleRange { /* TODO(fclem): Move to somewhere more appropriated after cleaning up the header dependencies. */ struct ObjectRef { - Object *object; + friend class ObjectKey; + friend DupliCacheManager; + + private: /** Duplicated object that corresponds to the current object. */ - DupliObject *dupli_object; + DupliObject *dupli_object_; /** Object that created the dupli-list the current object is part of. */ - Object *dupli_parent; + Object *dupli_parent_; + + public: + Object *object; /** Unique handle per object ref. */ ResourceHandleRange handle; @@ -94,8 +118,231 @@ struct ObjectRef { /* Is the object coming from a Dupli system. */ bool is_dupli() const { - return dupli_object != nullptr; + return dupli_object_ != nullptr; + } + + bool is_active(const Object *active_object) const + { + return (dupli_object_ ? dupli_parent_ : object) == active_object; + } + + float random() const + { + if (dupli_object_ == nullptr) { + /* TODO(fclem): this is rather costly to do at draw time. Maybe we can + * put it in ob->runtime and make depsgraph ensure it is up to date. */ + return BLI_hash_int_2d(BLI_hash_string(object->id.name + 2), 0) * (1.0f / (float)0xFFFFFFFF); + } + return dupli_object_->random_id * (1.0f / (float)0xFFFFFFFF); + } + + bool find_rgba_attribute(const GPUUniformAttr &attr, float r_value[4]) const + { + /* If requesting instance data, check the parent particle system and object. */ + if (attr.use_dupli) { + return BKE_object_dupli_find_rgba_attribute( + object, dupli_object_, dupli_parent_, attr.name, r_value); + } + return BKE_object_dupli_find_rgba_attribute(object, nullptr, nullptr, attr.name, r_value); + } + + LightLinking *light_linking() const + { + /* TODO: Could this be handled directly by deg_iterator_duplis_step? */ + return dupli_parent_ ? dupli_parent_->light_linking : object->light_linking; + } + + int recalc_flags(uint64_t last_update) const + { + /* TODO: There should also be a way to get the the min last_update for all objects in the + * range. */ + auto get_flags = [&](const ObjectRuntimeHandle &runtime) { + int flags = 0; + SET_FLAG_FROM_TEST(flags, runtime.last_update_transform > last_update, ID_RECALC_TRANSFORM); + SET_FLAG_FROM_TEST(flags, runtime.last_update_geometry > last_update, ID_RECALC_GEOMETRY); + SET_FLAG_FROM_TEST(flags, runtime.last_update_shading > last_update, ID_RECALC_SHADING); + return flags; + }; + + int flags = get_flags(*object->runtime); + if (dupli_parent_) { + flags |= get_flags(*dupli_parent_->runtime); + } + + return flags; + } + + /* Particle data are stored in world space. If an object is instanced, the associated particle + * systems need to be offset appropriately. */ + float4x4 particles_matrix() const + { + /* TODO: Pass particle systems as a separate ObRef? */ + float4x4 dupli_mat = float4x4::identity(); + if (dupli_parent_ && dupli_object_) { + if (dupli_object_->type & OB_DUPLICOLLECTION) { + Collection *collection = dupli_parent_->instance_collection; + if (collection != nullptr) { + dupli_mat[3] -= float4(float3(collection->instance_offset), 0.0f); + } + dupli_mat = dupli_parent_->object_to_world() * dupli_mat; + } + else { + dupli_mat = object->object_to_world() * math::invert(dupli_object_->ob->object_to_world()); + } + } + return dupli_mat; + } + + int preview_instance_index() const + { + if (dupli_object_) { + return dupli_object_->preview_instance_index; + } + return -1; + } + + const blender::bke::GeometrySet *preview_base_geometry() const + { + if (dupli_object_) { + return dupli_object_->preview_base_geometry; + } + return nullptr; + } + + bool parent_is_in_edit_paint_mode(const Object *active_object, + eObjectMode ob_mode, + eContextObjectMode ctx_mode) const + { + /* TODO: Deduplicate code with Overlay engine. + * Move to BKE ? Or check if T72490 is still relevant. */ + + if (!dupli_parent_ || active_object != dupli_parent_) { + return false; + } + + if (object->base_flag & BASE_FROM_DUPLI) { + /* TODO: Is this code reachable? */ + return false; + } + + if (dupli_parent_->sculpt && (dupli_parent_->sculpt->mode_type == OB_MODE_SCULPT)) { + return true; + } + + if (ob_mode & (OB_MODE_ALL_PAINT | OB_MODE_ALL_PAINT_GPENCIL)) { + return true; + } + + if (DRW_object_is_in_edit_mode(dupli_parent_)) { + /* Also check for context mode as the object mode is not 100% reliable. (see T72490) */ + switch (dupli_parent_->type) { + case OB_MESH: + return ctx_mode == CTX_MODE_EDIT_MESH; + case OB_ARMATURE: + return ctx_mode == CTX_MODE_EDIT_ARMATURE; + case OB_CURVES_LEGACY: + return ctx_mode == CTX_MODE_EDIT_CURVE; + case OB_SURF: + return ctx_mode == CTX_MODE_EDIT_SURFACE; + case OB_LATTICE: + return ctx_mode == CTX_MODE_EDIT_LATTICE; + case OB_MBALL: + return ctx_mode == CTX_MODE_EDIT_METABALL; + case OB_FONT: + return ctx_mode == CTX_MODE_EDIT_TEXT; + case OB_CURVES: + return ctx_mode == CTX_MODE_EDIT_CURVES; + case OB_POINTCLOUD: + return ctx_mode == CTX_MODE_EDIT_POINTCLOUD; + case OB_GREASE_PENCIL: + return ctx_mode == CTX_MODE_EDIT_GREASE_PENCIL; + case OB_VOLUME: + /* No edit mode yet. */ + return false; + } + } + return false; } }; +/* -------------------------------------------------------------------- */ +/** \name ObjectKey + * + * Unique key to identify each object in a hash-map. + * Note that we get a unique key for each object component. + * \{ */ + +class ObjectKey { + /** Hash value of the key. */ + uint64_t hash_value_ = 0; + /** Original Object or source object for duplis. */ + Object *ob_ = nullptr; + /** Original Parent object for duplis. */ + Object *parent_ = nullptr; + /** Dupli objects recursive unique identifier */ + int id_[MAX_DUPLI_RECUR]; + /** Used for particle system hair. */ + int sub_key_ = 0; + + public: + ObjectKey() = default; + + ObjectKey(const ObjectRef &ob_ref, int sub_key = 0) + { + ob_ = DEG_get_original(ob_ref.object); + hash_value_ = get_default_hash(ob_); + + if (DupliObject *dupli = ob_ref.dupli_object_) { + parent_ = ob_ref.dupli_parent_; + hash_value_ = get_default_hash(hash_value_, get_default_hash(parent_)); + for (int i : IndexRange(MAX_DUPLI_RECUR)) { + id_[i] = dupli->persistent_id[i]; + if (id_[i] == INT_MAX) { + break; + } + hash_value_ = get_default_hash(hash_value_, get_default_hash(id_[i])); + } + } + + if (sub_key != 0) { + sub_key_ = sub_key; + hash_value_ = get_default_hash(hash_value_, get_default_hash(sub_key_)); + } + } + + uint64_t hash() const + { + return hash_value_; + } + + bool operator==(const ObjectKey &k) const + { + if (hash_value_ != k.hash_value_) { + return false; + } + if (ob_ != k.ob_) { + return false; + } + if (parent_ != k.parent_) { + return false; + } + if (sub_key_ != k.sub_key_) { + return false; + } + if (parent_) { + for (int i : IndexRange(MAX_DUPLI_RECUR)) { + if (id_[i] != k.id_[i]) { + return false; + } + if (id_[i] == INT_MAX) { + break; + } + } + } + return true; + } +}; + +/** \} */ + }; // namespace blender::draw diff --git a/source/blender/draw/intern/draw_manager.hh b/source/blender/draw/intern/draw_manager.hh index c995028c09b..e1c9405a84b 100644 --- a/source/blender/draw/intern/draw_manager.hh +++ b/source/blender/draw/intern/draw_manager.hh @@ -326,7 +326,7 @@ inline ResourceHandleRange Manager::unique_handle(const ObjectRef &ref) inline ResourceHandleRange Manager::resource_handle(const ObjectRef &ref, float inflate_bounds) { - bool is_active_object = (ref.dupli_object ? ref.dupli_parent : ref.object) == object_active; + bool is_active_object = ref.is_active(object_active); matrix_buf.current().get_or_resize(resource_len_).sync(*ref.object); bounds_buf.current().get_or_resize(resource_len_).sync(*ref.object, inflate_bounds); infos_buf.current().get_or_resize(resource_len_).sync(ref, is_active_object); @@ -338,7 +338,6 @@ inline ResourceHandle Manager::resource_handle(const ObjectRef &ref, const float3 *bounds_center, const float3 *bounds_half_extent) { - bool is_active_object = (ref.dupli_object ? ref.dupli_parent : ref.object) == object_active; if (model_matrix) { matrix_buf.current().get_or_resize(resource_len_).sync(*model_matrix); } @@ -351,7 +350,7 @@ inline ResourceHandle Manager::resource_handle(const ObjectRef &ref, else { bounds_buf.current().get_or_resize(resource_len_).sync(*ref.object); } - infos_buf.current().get_or_resize(resource_len_).sync(ref, is_active_object); + infos_buf.current().get_or_resize(resource_len_).sync(ref, ref.is_active(object_active)); return ResourceHandle(resource_len_++, (ref.object->transflag & OB_NEG_SCALE) != 0); } @@ -376,10 +375,9 @@ inline ResourceHandle Manager::resource_handle(const float4x4 &model_matrix, inline ResourceHandle Manager::resource_handle_for_psys(const ObjectRef &ref, const float4x4 &model_matrix) { - bool is_active_object = (ref.dupli_object ? ref.dupli_parent : ref.object) == object_active; matrix_buf.current().get_or_resize(resource_len_).sync(model_matrix); bounds_buf.current().get_or_resize(resource_len_).sync(); - infos_buf.current().get_or_resize(resource_len_).sync(ref, is_active_object); + infos_buf.current().get_or_resize(resource_len_).sync(ref, ref.is_active(object_active)); return ResourceHandle(resource_len_++, (ref.object->transflag & OB_NEG_SCALE) != 0); } diff --git a/source/blender/draw/intern/draw_resource.cc b/source/blender/draw/intern/draw_resource.cc index c983909a89e..b94d546dd0f 100644 --- a/source/blender/draw/intern/draw_resource.cc +++ b/source/blender/draw/intern/draw_resource.cc @@ -19,15 +19,8 @@ bool ObjectAttribute::sync(const blender::draw::ObjectRef &ref, const GPUUniformAttr &attr) { /* This function mirrors `lookup_instance_property` in `cycles/blender/blender_object.cpp`. */ - hash_code = attr.hash_code; - - /* If requesting instance data, check the parent particle system and object. */ - if (attr.use_dupli) { - return BKE_object_dupli_find_rgba_attribute( - ref.object, ref.dupli_object, ref.dupli_parent, attr.name, &data_x); - } - return BKE_object_dupli_find_rgba_attribute(ref.object, nullptr, nullptr, attr.name, &data_x); + return ref.find_rgba_attribute(attr, &data_x); } /** \} */ diff --git a/source/blender/draw/intern/draw_resource.hh b/source/blender/draw/intern/draw_resource.hh index 17dc8ae0875..f74e1765297 100644 --- a/source/blender/draw/intern/draw_resource.hh +++ b/source/blender/draw/intern/draw_resource.hh @@ -75,8 +75,7 @@ inline void ObjectInfos::sync(const blender::draw::ObjectRef ref, bool is_active object_attrs_offset = 0; light_and_shadow_set_membership = 0; - LightLinking *light_linking = (ref.dupli_parent) != nullptr ? ref.dupli_parent->light_linking : - ref.object->light_linking; + LightLinking *light_linking = ref.light_linking(); if (light_linking) { light_and_shadow_set_membership |= light_linking->runtime.receiver_light_set; light_and_shadow_set_membership |= light_linking->runtime.blocker_shadow_set << 8; @@ -109,15 +108,7 @@ inline void ObjectInfos::sync(const blender::draw::ObjectRef ref, bool is_active shadow_terminator_normal_offset = 0.0f; } - if (ref.dupli_object == nullptr) { - /* TODO(fclem): this is rather costly to do at draw time. Maybe we can - * put it in ob->runtime and make depsgraph ensure it is up to date. */ - random = BLI_hash_int_2d(BLI_hash_string(ref.object->id.name + 2), 0) * - (1.0f / (float)0xFFFFFFFF); - } - else { - random = ref.dupli_object->random_id * (1.0f / (float)0xFFFFFFFF); - } + random = ref.random(); if (ref.object->data == nullptr) { orco_add = float3(0.0f);