Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--intern/cycles/blender/blender_curves.cpp42
-rw-r--r--intern/cycles/blender/blender_geometry.cpp42
-rw-r--r--intern/cycles/blender/blender_light.cpp15
-rw-r--r--intern/cycles/blender/blender_mesh.cpp61
-rw-r--r--intern/cycles/blender/blender_object.cpp26
-rw-r--r--intern/cycles/blender/blender_sync.h29
-rw-r--r--intern/cycles/blender/blender_util.h49
-rw-r--r--intern/cycles/blender/blender_volume.cpp21
-rw-r--r--source/blender/blenkernel/BKE_duplilist.h4
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.h2
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh45
-rw-r--r--source/blender/blenkernel/BKE_object.h2
-rw-r--r--source/blender/blenkernel/intern/geometry_component_instances.cc15
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc37
-rw-r--r--source/blender/blenkernel/intern/geometry_set_instances.cc12
-rw-r--r--source/blender/blenkernel/intern/object.c13
-rw-r--r--source/blender/blenkernel/intern/object_dupli.cc97
-rw-r--r--source/blender/blenlib/BLI_user_counter.hh12
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_query.h10
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_iter.cc138
-rw-r--r--source/blender/draw/intern/draw_manager.c64
-rw-r--r--source/blender/draw/intern/draw_manager.h15
-rw-r--r--source/blender/editors/object/object_add.c10
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh5
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc5
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_layout.cc17
-rw-r--r--source/blender/editors/transform/transform_snap_object.c4
-rw-r--r--source/blender/makesdna/DNA_node_types.h1
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_instance.cc17
30 files changed, 501 insertions, 314 deletions
diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp
index 85d886fd850..6fe5ea41fff 100644
--- a/intern/cycles/blender/blender_curves.cpp
+++ b/intern/cycles/blender/blender_curves.cpp
@@ -526,8 +526,13 @@ bool BlenderSync::object_has_particle_hair(BL::Object b_ob)
/* Old particle hair. */
void BlenderSync::sync_particle_hair(
- Hair *hair, BL::Mesh &b_mesh, BL::Object &b_ob, bool motion, int motion_step)
+ Hair *hair, BL::Mesh &b_mesh, BObjectInfo &b_ob_info, bool motion, int motion_step)
{
+ if (!b_ob_info.is_real_object_data()) {
+ return;
+ }
+ BL::Object b_ob = b_ob_info.real_object;
+
/* obtain general settings */
if (b_ob.mode() == b_ob.mode_PARTICLE_EDIT || b_ob.mode() == b_ob.mode_EDIT) {
return;
@@ -788,10 +793,10 @@ static void export_hair_curves_motion(Hair *hair, BL::Hair b_hair, int motion_st
}
/* Hair object. */
-void BlenderSync::sync_hair(Hair *hair, BL::Object &b_ob, bool motion, int motion_step)
+void BlenderSync::sync_hair(Hair *hair, BObjectInfo &b_ob_info, bool motion, int motion_step)
{
/* Convert Blender hair to Cycles curves. */
- BL::Hair b_hair(b_ob.data());
+ BL::Hair b_hair(b_ob_info.object_data);
if (motion) {
export_hair_curves_motion(hair, b_hair, motion_step);
}
@@ -800,16 +805,16 @@ void BlenderSync::sync_hair(Hair *hair, BL::Object &b_ob, bool motion, int motio
}
}
#else
-void BlenderSync::sync_hair(Hair *hair, BL::Object &b_ob, bool motion, int motion_step)
+void BlenderSync::sync_hair(Hair *hair, BObjectInfo &b_ob_info, bool motion, int motion_step)
{
(void)hair;
- (void)b_ob;
+ (void)b_ob_info;
(void)motion;
(void)motion_step;
}
#endif
-void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Hair *hair)
+void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Hair *hair)
{
/* make a copy of the shaders as the caller in the main thread still need them for syncing the
* attributes */
@@ -819,19 +824,19 @@ void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Hair *ha
new_hair.set_used_shaders(used_shaders);
if (view_layer.use_hair) {
- if (b_ob.type() == BL::Object::type_HAIR) {
+ if (b_ob_info.object_data.is_a(&RNA_Hair)) {
/* Hair object. */
- sync_hair(&new_hair, b_ob, false);
+ sync_hair(&new_hair, b_ob_info, false);
}
else {
/* Particle hair. */
bool need_undeformed = new_hair.need_attribute(scene, ATTR_STD_GENERATED);
BL::Mesh b_mesh = object_to_mesh(
- b_data, b_ob, b_depsgraph, need_undeformed, Mesh::SUBDIVISION_NONE);
+ b_data, b_ob_info, b_depsgraph, need_undeformed, Mesh::SUBDIVISION_NONE);
if (b_mesh) {
- sync_particle_hair(&new_hair, b_mesh, b_ob, false);
- free_object_to_mesh(b_data, b_ob, b_mesh);
+ sync_particle_hair(&new_hair, b_mesh, b_ob_info, false);
+ free_object_to_mesh(b_data, b_ob_info, b_mesh);
}
}
}
@@ -859,7 +864,7 @@ void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Hair *ha
}
void BlenderSync::sync_hair_motion(BL::Depsgraph b_depsgraph,
- BL::Object b_ob,
+ BObjectInfo &b_ob_info,
Hair *hair,
int motion_step)
{
@@ -869,18 +874,19 @@ void BlenderSync::sync_hair_motion(BL::Depsgraph b_depsgraph,
}
/* Export deformed coordinates. */
- if (ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) {
- if (b_ob.type() == BL::Object::type_HAIR) {
+ if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) {
+ if (b_ob_info.object_data.is_a(&RNA_Hair)) {
/* Hair object. */
- sync_hair(hair, b_ob, true, motion_step);
+ sync_hair(hair, b_ob_info, true, motion_step);
return;
}
else {
/* Particle hair. */
- BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_depsgraph, false, Mesh::SUBDIVISION_NONE);
+ BL::Mesh b_mesh = object_to_mesh(
+ b_data, b_ob_info, b_depsgraph, false, Mesh::SUBDIVISION_NONE);
if (b_mesh) {
- sync_particle_hair(hair, b_mesh, b_ob, true, motion_step);
- free_object_to_mesh(b_data, b_ob, b_mesh);
+ sync_particle_hair(hair, b_mesh, b_ob_info, true, motion_step);
+ free_object_to_mesh(b_data, b_ob_info, b_mesh);
return;
}
}
diff --git a/intern/cycles/blender/blender_geometry.cpp b/intern/cycles/blender/blender_geometry.cpp
index a009018f357..acc089a286c 100644
--- a/intern/cycles/blender/blender_geometry.cpp
+++ b/intern/cycles/blender/blender_geometry.cpp
@@ -29,13 +29,15 @@
CCL_NAMESPACE_BEGIN
-static Geometry::Type determine_geom_type(BL::Object &b_ob, bool use_particle_hair)
+static Geometry::Type determine_geom_type(BObjectInfo &b_ob_info, bool use_particle_hair)
{
- if (b_ob.type() == BL::Object::type_HAIR || use_particle_hair) {
+ if (b_ob_info.object_data.is_a(&RNA_Hair) || use_particle_hair) {
return Geometry::HAIR;
}
- if (b_ob.type() == BL::Object::type_VOLUME || object_fluid_gas_domain_find(b_ob)) {
+ if (b_ob_info.object_data.is_a(&RNA_Volume) ||
+ (b_ob_info.object_data == b_ob_info.real_object.data() &&
+ object_fluid_gas_domain_find(b_ob_info.real_object))) {
return Geometry::VOLUME;
}
@@ -71,20 +73,17 @@ array<Node *> BlenderSync::find_used_shaders(BL::Object &b_ob)
}
Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
- BL::Object &b_ob,
- BL::Object &b_ob_instance,
+ BObjectInfo &b_ob_info,
bool object_updated,
bool use_particle_hair,
TaskPool *task_pool)
{
/* Test if we can instance or if the object is modified. */
- BL::ID b_ob_data = b_ob.data();
- BL::ID b_key_id = (BKE_object_is_modified(b_ob)) ? b_ob_instance : b_ob_data;
- Geometry::Type geom_type = determine_geom_type(b_ob, use_particle_hair);
- GeometryKey key(b_key_id.ptr.data, geom_type);
+ Geometry::Type geom_type = determine_geom_type(b_ob_info, use_particle_hair);
+ GeometryKey key(b_ob_info.object_data, geom_type);
/* Find shader indices. */
- array<Node *> used_shaders = find_used_shaders(b_ob);
+ array<Node *> used_shaders = find_used_shaders(b_ob_info.iter_object);
/* Ensure we only sync instanced geometry once. */
Geometry *geom = geometry_map.find(key);
@@ -111,7 +110,7 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
}
else {
/* Test if we need to update existing geometry. */
- sync = geometry_map.update(geom, b_key_id);
+ sync = geometry_map.update(geom, b_ob_info.object_data);
}
if (!sync) {
@@ -144,7 +143,7 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
geometry_synced.insert(geom);
- geom->name = ustring(b_ob_data.name().c_str());
+ geom->name = ustring(b_ob_info.object_data.name().c_str());
/* Store the shaders immediately for the object attribute code. */
geom->set_used_shaders(used_shaders);
@@ -153,19 +152,19 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
if (progress.get_cancel())
return;
- progress.set_sync_status("Synchronizing object", b_ob.name());
+ progress.set_sync_status("Synchronizing object", b_ob_info.real_object.name());
if (geom_type == Geometry::HAIR) {
Hair *hair = static_cast<Hair *>(geom);
- sync_hair(b_depsgraph, b_ob, hair);
+ sync_hair(b_depsgraph, b_ob_info, hair);
}
else if (geom_type == Geometry::VOLUME) {
Volume *volume = static_cast<Volume *>(geom);
- sync_volume(b_ob, volume);
+ sync_volume(b_ob_info, volume);
}
else {
Mesh *mesh = static_cast<Mesh *>(geom);
- sync_mesh(b_depsgraph, b_ob, mesh);
+ sync_mesh(b_depsgraph, b_ob_info, mesh);
}
};
@@ -181,7 +180,7 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
}
void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph,
- BL::Object &b_ob,
+ BObjectInfo &b_ob_info,
Object *object,
float motion_time,
bool use_particle_hair,
@@ -210,16 +209,17 @@ void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph,
if (progress.get_cancel())
return;
- if (b_ob.type() == BL::Object::type_HAIR || use_particle_hair) {
+ if (b_ob_info.object_data.is_a(&RNA_Hair) || use_particle_hair) {
Hair *hair = static_cast<Hair *>(geom);
- sync_hair_motion(b_depsgraph, b_ob, hair, motion_step);
+ sync_hair_motion(b_depsgraph, b_ob_info, hair, motion_step);
}
- else if (b_ob.type() == BL::Object::type_VOLUME || object_fluid_gas_domain_find(b_ob)) {
+ else if (b_ob_info.object_data.is_a(&RNA_Volume) ||
+ object_fluid_gas_domain_find(b_ob_info.real_object)) {
/* No volume motion blur support yet. */
}
else {
Mesh *mesh = static_cast<Mesh *>(geom);
- sync_mesh_motion(b_depsgraph, b_ob, mesh, motion_step);
+ sync_mesh_motion(b_depsgraph, b_ob_info, mesh, motion_step);
}
};
diff --git a/intern/cycles/blender/blender_light.cpp b/intern/cycles/blender/blender_light.cpp
index 50cd9e3db5c..542028f4b2f 100644
--- a/intern/cycles/blender/blender_light.cpp
+++ b/intern/cycles/blender/blender_light.cpp
@@ -27,15 +27,14 @@ CCL_NAMESPACE_BEGIN
void BlenderSync::sync_light(BL::Object &b_parent,
int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
- BL::Object &b_ob,
- BL::Object &b_ob_instance,
+ BObjectInfo &b_ob_info,
int random_id,
Transform &tfm,
bool *use_portal)
{
/* test if we need to sync */
- ObjectKey key(b_parent, persistent_id, b_ob_instance, false);
- BL::Light b_light(b_ob.data());
+ ObjectKey key(b_parent, persistent_id, b_ob_info.real_object, false);
+ BL::Light b_light(b_ob_info.object_data);
Light *light = light_map.find(key);
@@ -44,7 +43,7 @@ void BlenderSync::sync_light(BL::Object &b_parent,
const bool tfm_updated = (light && light->get_tfm() != tfm);
/* Update if either object or light data changed. */
- if (!light_map.add_or_update(&light, b_ob, b_parent, key) && !tfm_updated) {
+ if (!light_map.add_or_update(&light, b_ob_info.real_object, b_parent, key) && !tfm_updated) {
Shader *shader;
if (!shader_map.add_or_update(&shader, b_light)) {
if (light->get_is_portal())
@@ -139,11 +138,11 @@ void BlenderSync::sync_light(BL::Object &b_parent,
light->set_max_bounces(get_int(clight, "max_bounces"));
- if (b_ob != b_ob_instance) {
+ if (b_ob_info.real_object != b_ob_info.iter_object) {
light->set_random_id(random_id);
}
else {
- light->set_random_id(hash_uint2(hash_string(b_ob.name().c_str()), 0));
+ light->set_random_id(hash_uint2(hash_string(b_ob_info.real_object.name().c_str()), 0));
}
if (light->get_light_type() == LIGHT_AREA)
@@ -155,7 +154,7 @@ void BlenderSync::sync_light(BL::Object &b_parent,
*use_portal = true;
/* visibility */
- uint visibility = object_ray_visibility(b_ob);
+ uint visibility = object_ray_visibility(b_ob_info.real_object);
light->set_use_diffuse((visibility & PATH_RAY_DIFFUSE) != 0);
light->set_use_glossy((visibility & PATH_RAY_GLOSSY) != 0);
light->set_use_transmission((visibility & PATH_RAY_TRANSMIT) != 0);
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp
index ebba6981502..9bb3447f56b 100644
--- a/intern/cycles/blender/blender_mesh.cpp
+++ b/intern/cycles/blender/blender_mesh.cpp
@@ -999,12 +999,14 @@ static void create_mesh(Scene *scene,
static void create_subd_mesh(Scene *scene,
Mesh *mesh,
- BL::Object &b_ob,
+ BObjectInfo &b_ob_info,
BL::Mesh &b_mesh,
const array<Node *> &used_shaders,
float dicing_rate,
int max_subdivisions)
{
+ BL::Object b_ob = b_ob_info.real_object;
+
BL::SubsurfModifier subsurf_mod(b_ob.modifiers[b_ob.modifiers.length() - 1]);
bool subdivide_uvs = subsurf_mod.uv_smooth() != BL::SubsurfModifier::uv_smooth_NONE;
@@ -1043,7 +1045,7 @@ static void create_subd_mesh(Scene *scene,
*
* NOTE: This code is run prior to object motion blur initialization. so can not access properties
* set by `sync_object_motion_init()`. */
-static bool mesh_need_motion_attribute(BL::Object &b_ob, Scene *scene)
+static bool mesh_need_motion_attribute(BObjectInfo &b_ob_info, Scene *scene)
{
const Scene::MotionType need_motion = scene->need_motion();
if (need_motion == Scene::MOTION_NONE) {
@@ -1060,7 +1062,7 @@ static bool mesh_need_motion_attribute(BL::Object &b_ob, Scene *scene)
* - Motion attribute expects non-zero time steps.
*
* Avoid adding motion attributes if the motion blur will enforce 0 motion steps. */
- PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
+ PointerRNA cobject = RNA_pointer_get(&b_ob_info.real_object.ptr, "cycles");
const bool use_motion = get_boolean(cobject, "use_motion_blur");
if (!use_motion) {
return false;
@@ -1072,12 +1074,13 @@ static bool mesh_need_motion_attribute(BL::Object &b_ob, Scene *scene)
return true;
}
-static void sync_mesh_cached_velocities(BL::Object &b_ob, Scene *scene, Mesh *mesh)
+static void sync_mesh_cached_velocities(BObjectInfo &b_ob_info, Scene *scene, Mesh *mesh)
{
- if (!mesh_need_motion_attribute(b_ob, scene)) {
+ if (!mesh_need_motion_attribute(b_ob_info, scene)) {
return;
}
+ BL::Object b_ob = b_ob_info.real_object;
BL::MeshSequenceCacheModifier b_mesh_cache = object_mesh_cache_find(b_ob, true, nullptr);
if (!b_mesh_cache) {
@@ -1118,12 +1121,16 @@ static void sync_mesh_cached_velocities(BL::Object &b_ob, Scene *scene, Mesh *me
}
}
-static void sync_mesh_fluid_motion(BL::Object &b_ob, Scene *scene, Mesh *mesh)
+static void sync_mesh_fluid_motion(BObjectInfo &b_ob_info, Scene *scene, Mesh *mesh)
{
- if (!mesh_need_motion_attribute(b_ob, scene)) {
+ if (!b_ob_info.is_real_object_data()) {
+ return;
+ }
+ if (!mesh_need_motion_attribute(b_ob_info, scene)) {
return;
}
+ BL::Object b_ob = b_ob_info.real_object;
BL::FluidDomainSettings b_fluid_domain = object_fluid_liquid_domain_find(b_ob);
if (!b_fluid_domain)
@@ -1157,7 +1164,7 @@ static void sync_mesh_fluid_motion(BL::Object &b_ob, Scene *scene, Mesh *mesh)
}
}
-void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh)
+void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Mesh *mesh)
{
/* make a copy of the shaders as the caller in the main thread still need them for syncing the
* attributes */
@@ -1170,20 +1177,21 @@ void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *me
/* Adaptive subdivision setup. Not for baking since that requires
* exact mapping to the Blender mesh. */
if (!scene->bake_manager->get_baking()) {
- new_mesh.set_subdivision_type(object_subdivision_type(b_ob, preview, experimental));
+ new_mesh.set_subdivision_type(
+ object_subdivision_type(b_ob_info.real_object, preview, experimental));
}
/* For some reason, meshes do not need this... */
bool need_undeformed = new_mesh.need_attribute(scene, ATTR_STD_GENERATED);
BL::Mesh b_mesh = object_to_mesh(
- b_data, b_ob, b_depsgraph, need_undeformed, new_mesh.get_subdivision_type());
+ b_data, b_ob_info, b_depsgraph, need_undeformed, new_mesh.get_subdivision_type());
if (b_mesh) {
/* Sync mesh itself. */
if (new_mesh.get_subdivision_type() != Mesh::SUBDIVISION_NONE)
create_subd_mesh(scene,
&new_mesh,
- b_ob,
+ b_ob_info,
b_mesh,
new_mesh.get_used_shaders(),
dicing_rate,
@@ -1191,15 +1199,15 @@ void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *me
else
create_mesh(scene, &new_mesh, b_mesh, new_mesh.get_used_shaders(), false);
- free_object_to_mesh(b_data, b_ob, b_mesh);
+ free_object_to_mesh(b_data, b_ob_info, b_mesh);
}
}
/* cached velocities (e.g. from alembic archive) */
- sync_mesh_cached_velocities(b_ob, scene, &new_mesh);
+ sync_mesh_cached_velocities(b_ob_info, scene, &new_mesh);
/* mesh fluid motion mantaflow */
- sync_mesh_fluid_motion(b_ob, scene, &new_mesh);
+ sync_mesh_fluid_motion(b_ob_info, scene, &new_mesh);
/* update original sockets */
@@ -1230,18 +1238,19 @@ void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *me
}
void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
- BL::Object b_ob,
+ BObjectInfo &b_ob_info,
Mesh *mesh,
int motion_step)
{
/* Fluid motion blur already exported. */
- BL::FluidDomainSettings b_fluid_domain = object_fluid_liquid_domain_find(b_ob);
+ BL::FluidDomainSettings b_fluid_domain = object_fluid_liquid_domain_find(b_ob_info.real_object);
if (b_fluid_domain) {
return;
}
/* Cached motion blur already exported. */
- BL::MeshSequenceCacheModifier mesh_cache = object_mesh_cache_find(b_ob, true, nullptr);
+ BL::MeshSequenceCacheModifier mesh_cache = object_mesh_cache_find(
+ b_ob_info.real_object, true, nullptr);
if (mesh_cache) {
return;
}
@@ -1255,11 +1264,13 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
/* Skip objects without deforming modifiers. this is not totally reliable,
* would need a more extensive check to see which objects are animated. */
BL::Mesh b_mesh(PointerRNA_NULL);
- if (ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) {
+ if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) {
/* get derived mesh */
- b_mesh = object_to_mesh(b_data, b_ob, b_depsgraph, false, Mesh::SUBDIVISION_NONE);
+ b_mesh = object_to_mesh(b_data, b_ob_info, b_depsgraph, false, Mesh::SUBDIVISION_NONE);
}
+ const std::string ob_name = b_ob_info.real_object.name();
+
/* TODO(sergey): Perform preliminary check for number of vertices. */
if (b_mesh) {
/* Export deformed coordinates. */
@@ -1295,17 +1306,17 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
memcmp(mP, &mesh->get_verts()[0], sizeof(float3) * numverts) == 0) {
/* no motion, remove attributes again */
if (b_mesh.vertices.length() != numverts) {
- VLOG(1) << "Topology differs, disabling motion blur for object " << b_ob.name();
+ VLOG(1) << "Topology differs, disabling motion blur for object " << ob_name;
}
else {
- VLOG(1) << "No actual deformation motion for object " << b_ob.name();
+ VLOG(1) << "No actual deformation motion for object " << ob_name;
}
mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
if (attr_mN)
mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_NORMAL);
}
else if (motion_step > 0) {
- VLOG(1) << "Filling deformation motion for object " << b_ob.name();
+ VLOG(1) << "Filling deformation motion for object " << ob_name;
/* motion, fill up previous steps that we might have skipped because
* they had no motion, but we need them anyway now */
float3 *P = &mesh->get_verts()[0];
@@ -1319,8 +1330,8 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
}
else {
if (b_mesh.vertices.length() != numverts) {
- VLOG(1) << "Topology differs, discarding motion blur for object " << b_ob.name()
- << " at time " << motion_step;
+ VLOG(1) << "Topology differs, discarding motion blur for object " << ob_name << " at time "
+ << motion_step;
memcpy(mP, &mesh->get_verts()[0], sizeof(float3) * numverts);
if (mN != NULL) {
memcpy(mN, attr_N->data_float3(), sizeof(float3) * numverts);
@@ -1328,7 +1339,7 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
}
}
- free_object_to_mesh(b_data, b_ob, b_mesh);
+ free_object_to_mesh(b_data, b_ob_info, b_mesh);
return;
}
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index 5d98b61b409..2243baca0b2 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -154,7 +154,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
const bool is_instance = b_instance.is_instance();
BL::Object b_ob = b_instance.object();
BL::Object b_parent = is_instance ? b_instance.parent() : b_instance.object();
- BL::Object b_ob_instance = is_instance ? b_instance.instance_object() : b_ob;
+ BObjectInfo b_ob_info{b_ob, is_instance ? b_instance.instance_object() : b_ob, b_ob.data()};
const bool motion = motion_time != 0.0f;
/*const*/ Transform tfm = get_transform(b_ob.matrix_world());
int *persistent_id = NULL;
@@ -178,8 +178,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
{
sync_light(b_parent,
persistent_id,
- b_ob,
- b_ob_instance,
+ b_ob_info,
is_instance ? b_instance.random_id() : 0,
tfm,
use_portal);
@@ -231,7 +230,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
TaskPool *object_geom_task_pool = (is_instance) ? NULL : geom_task_pool;
/* key to lookup object */
- ObjectKey key(b_parent, persistent_id, b_ob_instance, use_particle_hair);
+ ObjectKey key(b_parent, persistent_id, b_ob_info.real_object, use_particle_hair);
Object *object;
/* motion vector case */
@@ -249,12 +248,8 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
/* mesh deformation */
if (object->get_geometry())
- sync_geometry_motion(b_depsgraph,
- b_ob_instance,
- object,
- motion_time,
- use_particle_hair,
- object_geom_task_pool);
+ sync_geometry_motion(
+ b_depsgraph, b_ob_info, object, motion_time, use_particle_hair, object_geom_task_pool);
}
return object;
@@ -265,15 +260,8 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
(tfm != object->get_tfm());
/* mesh sync */
- /* b_ob is owned by the iterator and will go out of scope at the end of the block.
- * b_ob_instance is the original object and will remain valid for deferred geometry
- * sync. */
- Geometry *geometry = sync_geometry(b_depsgraph,
- b_ob_instance,
- b_ob_instance,
- object_updated,
- use_particle_hair,
- object_geom_task_pool);
+ Geometry *geometry = sync_geometry(
+ b_depsgraph, b_ob_info, object_updated, use_particle_hair, object_geom_task_pool);
object->set_geometry(geometry);
/* special case not tracked by object update flags */
diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h
index 44322dda6b9..76e8f23864c 100644
--- a/intern/cycles/blender/blender_sync.h
+++ b/intern/cycles/blender/blender_sync.h
@@ -23,6 +23,7 @@
#include "RNA_types.h"
#include "blender/blender_id_map.h"
+#include "blender/blender_util.h"
#include "blender/blender_viewport.h"
#include "render/scene.h"
@@ -158,18 +159,24 @@ class BlenderSync {
bool sync_object_attributes(BL::DepsgraphObjectInstance &b_instance, Object *object);
/* Volume */
- void sync_volume(BL::Object &b_ob, Volume *volume);
+ void sync_volume(BObjectInfo &b_ob_info, Volume *volume);
/* Mesh */
- void sync_mesh(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh);
- void sync_mesh_motion(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh, int motion_step);
+ void sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Mesh *mesh);
+ void sync_mesh_motion(BL::Depsgraph b_depsgraph,
+ BObjectInfo &b_ob_info,
+ Mesh *mesh,
+ int motion_step);
/* Hair */
- void sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Hair *hair);
- void sync_hair_motion(BL::Depsgraph b_depsgraph, BL::Object b_ob, Hair *hair, int motion_step);
- void sync_hair(Hair *hair, BL::Object &b_ob, bool motion, int motion_step = 0);
+ void sync_hair(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Hair *hair);
+ void sync_hair_motion(BL::Depsgraph b_depsgraph,
+ BObjectInfo &b_ob_info,
+ Hair *hair,
+ int motion_step);
+ void sync_hair(Hair *hair, BObjectInfo &b_ob_info, bool motion, int motion_step = 0);
void sync_particle_hair(
- Hair *hair, BL::Mesh &b_mesh, BL::Object &b_ob, bool motion, int motion_step = 0);
+ Hair *hair, BL::Mesh &b_mesh, BObjectInfo &b_ob_info, bool motion, int motion_step = 0);
bool object_has_particle_hair(BL::Object b_ob);
/* Camera */
@@ -178,14 +185,13 @@ class BlenderSync {
/* Geometry */
Geometry *sync_geometry(BL::Depsgraph &b_depsgrpah,
- BL::Object &b_ob,
- BL::Object &b_ob_instance,
+ BObjectInfo &b_ob_info,
bool object_updated,
bool use_particle_hair,
TaskPool *task_pool);
void sync_geometry_motion(BL::Depsgraph &b_depsgraph,
- BL::Object &b_ob,
+ BObjectInfo &b_ob_info,
Object *object,
float motion_time,
bool use_particle_hair,
@@ -194,8 +200,7 @@ class BlenderSync {
/* Light */
void sync_light(BL::Object &b_parent,
int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
- BL::Object &b_ob,
- BL::Object &b_ob_instance,
+ BObjectInfo &b_ob_info,
int random_id,
Transform &tfm,
bool *use_portal);
diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h
index f6824f31b7b..e69531ea707 100644
--- a/intern/cycles/blender/blender_util.h
+++ b/intern/cycles/blender/blender_util.h
@@ -40,6 +40,28 @@ float *BKE_image_get_float_pixels_for_frame(void *image, int frame, int tile);
CCL_NAMESPACE_BEGIN
+struct BObjectInfo {
+ /* Object directly provided by the depsgraph iterator. This object is only valid during one
+ * iteration and must not be accessed afterwards. Transforms and visibility should be checked on
+ * this object. */
+ BL::Object iter_object;
+
+ /* This object remains alive even after the object iterator is done. It corresponds to one
+ * original object. It is the object that owns the object data below. */
+ BL::Object real_object;
+
+ /* The object-data referenced by the iter object. This is still valid after the depsgraph
+ * iterator is done. It might have a different type compared to real_object.data(). */
+ BL::ID object_data;
+
+ /* True when the current geometry is the data of the referenced object. False when it is a
+ * geometry instance that does not have a 1-to-1 relationship with an object. */
+ bool is_real_object_data() const
+ {
+ return const_cast<BL::Object &>(real_object).data() == object_data;
+ }
+};
+
typedef BL::ShaderNodeAttribute::attribute_type_enum BlenderAttributeType;
BlenderAttributeType blender_attribute_name_split_type(ustring name, string *r_real_name);
@@ -47,7 +69,7 @@ void python_thread_state_save(void **python_thread_state);
void python_thread_state_restore(void **python_thread_state);
static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
- BL::Object &object,
+ BObjectInfo &b_ob_info,
BL::Depsgraph & /*depsgraph*/,
bool /*calc_undeformed*/,
Mesh::SubdivisionType subdivision_type)
@@ -69,9 +91,9 @@ static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
#endif
BL::Mesh mesh(PointerRNA_NULL);
- if (object.type() == BL::Object::type_MESH) {
+ if (b_ob_info.object_data.is_a(&RNA_Mesh)) {
/* TODO: calc_undeformed is not used. */
- mesh = BL::Mesh(object.data());
+ mesh = BL::Mesh(b_ob_info.object_data);
/* Make a copy to split faces if we use autosmooth, otherwise not needed.
* Also in edit mode do we need to make a copy, to ensure data layers like
@@ -79,12 +101,15 @@ static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
if (mesh.is_editmode() ||
(mesh.use_auto_smooth() && subdivision_type == Mesh::SUBDIVISION_NONE)) {
BL::Depsgraph depsgraph(PointerRNA_NULL);
- mesh = object.to_mesh(false, depsgraph);
+ assert(b_ob_info.is_real_object_data());
+ mesh = b_ob_info.real_object.to_mesh(false, depsgraph);
}
}
else {
BL::Depsgraph depsgraph(PointerRNA_NULL);
- mesh = object.to_mesh(false, depsgraph);
+ if (b_ob_info.is_real_object_data()) {
+ mesh = b_ob_info.real_object.to_mesh(false, depsgraph);
+ }
}
#if 0
@@ -108,10 +133,14 @@ static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
}
static inline void free_object_to_mesh(BL::BlendData & /*data*/,
- BL::Object &object,
+ BObjectInfo &b_ob_info,
BL::Mesh &mesh)
{
+ if (!b_ob_info.is_real_object_data()) {
+ return;
+ }
/* Free mesh if we didn't just use the existing one. */
+ BL::Object object = b_ob_info.real_object;
if (object.data().ptr.data != mesh.ptr.data) {
object.to_mesh_clear();
}
@@ -219,9 +248,13 @@ static inline bool BKE_object_is_modified(BL::Object &self, BL::Scene &scene, bo
return self.is_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true : false;
}
-static inline bool BKE_object_is_deform_modified(BL::Object &self, BL::Scene &scene, bool preview)
+static inline bool BKE_object_is_deform_modified(BObjectInfo &self, BL::Scene &scene, bool preview)
{
- return self.is_deform_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true : false;
+ if (!self.is_real_object_data()) {
+ return false;
+ }
+ return self.real_object.is_deform_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true :
+ false;
}
static inline int render_resolution_x(BL::RenderSettings &b_render)
diff --git a/intern/cycles/blender/blender_volume.cpp b/intern/cycles/blender/blender_volume.cpp
index 772ab9f5c8a..0a5b19d7d4c 100644
--- a/intern/cycles/blender/blender_volume.cpp
+++ b/intern/cycles/blender/blender_volume.cpp
@@ -181,9 +181,12 @@ class BlenderSmokeLoader : public ImageLoader {
AttributeStandard attribute;
};
-static void sync_smoke_volume(Scene *scene, BL::Object &b_ob, Volume *volume, float frame)
+static void sync_smoke_volume(Scene *scene, BObjectInfo &b_ob_info, Volume *volume, float frame)
{
- BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob);
+ if (!b_ob_info.is_real_object_data()) {
+ return;
+ }
+ BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob_info.real_object);
if (!b_domain) {
return;
}
@@ -206,7 +209,7 @@ static void sync_smoke_volume(Scene *scene, BL::Object &b_ob, Volume *volume, fl
Attribute *attr = volume->attributes.add(std);
- ImageLoader *loader = new BlenderSmokeLoader(b_ob, std);
+ ImageLoader *loader = new BlenderSmokeLoader(b_ob_info.real_object, std);
ImageParams params;
params.frame = frame;
@@ -244,11 +247,11 @@ class BlenderVolumeLoader : public VDBImageLoader {
};
static void sync_volume_object(BL::BlendData &b_data,
- BL::Object &b_ob,
+ BObjectInfo &b_ob_info,
Scene *scene,
Volume *volume)
{
- BL::Volume b_volume(b_ob.data());
+ BL::Volume b_volume(b_ob_info.object_data);
b_volume.grids.load(b_data.ptr.data);
BL::VolumeRender b_render(b_volume.render());
@@ -296,19 +299,19 @@ static void sync_volume_object(BL::BlendData &b_data,
}
}
-void BlenderSync::sync_volume(BL::Object &b_ob, Volume *volume)
+void BlenderSync::sync_volume(BObjectInfo &b_ob_info, Volume *volume)
{
volume->clear(true);
if (view_layer.use_volumes) {
- if (b_ob.type() == BL::Object::type_VOLUME) {
+ if (b_ob_info.object_data.is_a(&RNA_Volume)) {
/* Volume object. Create only attributes, bounding mesh will then
* be automatically generated later. */
- sync_volume_object(b_data, b_ob, scene, volume);
+ sync_volume_object(b_data, b_ob_info, scene, volume);
}
else {
/* Smoke domain. */
- sync_smoke_volume(scene, b_ob, volume, b_scene.frame_current());
+ sync_smoke_volume(scene, b_ob_info, volume, b_scene.frame_current());
}
}
diff --git a/source/blender/blenkernel/BKE_duplilist.h b/source/blender/blenkernel/BKE_duplilist.h
index c142d5338d1..989b68f4ccb 100644
--- a/source/blender/blenkernel/BKE_duplilist.h
+++ b/source/blender/blenkernel/BKE_duplilist.h
@@ -31,6 +31,7 @@ struct ListBase;
struct Object;
struct ParticleSystem;
struct Scene;
+struct ID;
/* ---------------------------------------------------- */
/* Dupli-Geometry */
@@ -42,7 +43,10 @@ void free_object_duplilist(struct ListBase *lb);
typedef struct DupliObject {
struct DupliObject *next, *prev;
+ /* Object whose geometry is instanced. */
struct Object *ob;
+ /* Data owned by the object above that is instanced. This might not be the same as `ob->data`. */
+ struct ID *ob_data;
float mat[4][4];
float orco[3], uv[2];
diff --git a/source/blender/blenkernel/BKE_geometry_set.h b/source/blender/blenkernel/BKE_geometry_set.h
index 5f6a9ec7b91..17cdb9d6a42 100644
--- a/source/blender/blenkernel/BKE_geometry_set.h
+++ b/source/blender/blenkernel/BKE_geometry_set.h
@@ -41,7 +41,7 @@ typedef enum GeometryComponentType {
void BKE_geometry_set_free(struct GeometrySet *geometry_set);
-bool BKE_geometry_set_has_instances(const struct GeometrySet *geometry_set);
+bool BKE_object_has_geometry_set_instances(const struct Object *ob);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index 42e9ce82278..08b6cb951a8 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -283,6 +283,7 @@ struct GeometrySet {
void clear();
+ bool owns_direct_data() const;
void ensure_owns_direct_data();
/* Utility methods for creation. */
@@ -447,12 +448,14 @@ class InstanceReference {
None,
Object,
Collection,
+ GeometrySet,
};
private:
Type type_ = Type::None;
/** Depending on the type this is either null, an Object or Collection pointer. */
void *data_ = nullptr;
+ std::unique_ptr<GeometrySet> geometry_set_;
public:
InstanceReference() = default;
@@ -465,6 +468,19 @@ class InstanceReference {
{
}
+ InstanceReference(GeometrySet geometry_set)
+ : type_(Type::GeometrySet),
+ geometry_set_(std::make_unique<GeometrySet>(std::move(geometry_set)))
+ {
+ }
+
+ InstanceReference(const InstanceReference &src) : type_(src.type_), data_(src.data_)
+ {
+ if (src.type_ == Type::GeometrySet) {
+ geometry_set_ = std::make_unique<GeometrySet>(*src.geometry_set_);
+ }
+ }
+
Type type() const
{
return type_;
@@ -482,14 +498,37 @@ class InstanceReference {
return *(Collection *)data_;
}
+ const GeometrySet &geometry_set() const
+ {
+ BLI_assert(type_ == Type::GeometrySet);
+ return *geometry_set_;
+ }
+
+ bool owns_direct_data() const
+ {
+ if (type_ != Type::GeometrySet) {
+ /* The object and collection instances are not direct data. */
+ return true;
+ }
+ return geometry_set_->owns_direct_data();
+ }
+
+ void ensure_owns_direct_data()
+ {
+ if (type_ != Type::GeometrySet) {
+ return;
+ }
+ geometry_set_->ensure_owns_direct_data();
+ }
+
uint64_t hash() const
{
- return blender::get_default_hash(data_);
+ return blender::get_default_hash_2(data_, geometry_set_.get());
}
friend bool operator==(const InstanceReference &a, const InstanceReference &b)
{
- return a.data_ == b.data_;
+ return a.data_ == b.data_ && a.geometry_set_.get() == b.geometry_set_.get();
}
};
@@ -529,7 +568,7 @@ class InstancesComponent : public GeometryComponent {
void reserve(int min_capacity);
void resize(int capacity);
- int add_reference(InstanceReference reference);
+ int add_reference(const InstanceReference &reference);
void add_instance(int instance_handle, const blender::float4x4 &transform, const int id = -1);
blender::Span<InstanceReference> references() const;
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index a823602e341..31b3cd66cbb 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -458,6 +458,8 @@ void BKE_object_modifiers_lib_link_common(void *userData,
struct ID **idpoin,
int cb_flag);
+void BKE_object_replace_data_on_shallow_copy(struct Object *ob, struct ID *new_data);
+
struct PartEff;
struct PartEff *BKE_object_do_version_give_parteff_245(struct Object *ob);
diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc
index 3b1b7456162..26ef827d36d 100644
--- a/source/blender/blenkernel/intern/geometry_component_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_component_instances.cc
@@ -122,7 +122,7 @@ blender::Span<int> InstancesComponent::instance_ids() const
* If the reference exists already, the handle of the existing reference is returned.
* Otherwise a new handle is added.
*/
-int InstancesComponent::add_reference(InstanceReference reference)
+int InstancesComponent::add_reference(const InstanceReference &reference)
{
return references_.index_of_or_add_as(reference);
}
@@ -144,14 +144,23 @@ bool InstancesComponent::is_empty() const
bool InstancesComponent::owns_direct_data() const
{
- /* The object and collection instances are not direct data. Instance transforms are direct data
- * and are always owned. Therefore, instance components always own all their direct data. */
+ for (const InstanceReference &reference : references_) {
+ if (!reference.owns_direct_data()) {
+ return false;
+ }
+ }
return true;
}
void InstancesComponent::ensure_owns_direct_data()
{
BLI_assert(this->is_mutable());
+ for (const InstanceReference &const_reference : references_) {
+ /* Const cast is fine because we are not changing anything that would change the hash of the
+ * reference. */
+ InstanceReference &reference = const_cast<InstanceReference &>(const_reference);
+ reference.ensure_owns_direct_data();
+ }
}
static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids)
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index 07b4e715ea9..dafebef1812 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -218,6 +218,16 @@ void GeometrySet::ensure_owns_direct_data()
}
}
+bool GeometrySet::owns_direct_data() const
+{
+ for (const GeometryComponentPtr &component : components_.values()) {
+ if (!component->owns_direct_data()) {
+ return false;
+ }
+ }
+ return true;
+}
+
/* Returns a read-only mesh or null. */
const Mesh *GeometrySet::get_mesh_for_read() const
{
@@ -376,9 +386,32 @@ void BKE_geometry_set_free(GeometrySet *geometry_set)
delete geometry_set;
}
-bool BKE_geometry_set_has_instances(const GeometrySet *geometry_set)
+bool BKE_object_has_geometry_set_instances(const Object *ob)
{
- return geometry_set->get_component_for_read<InstancesComponent>() != nullptr;
+ const GeometrySet *geometry_set = ob->runtime.geometry_set_eval;
+ if (geometry_set == nullptr) {
+ return false;
+ }
+ if (geometry_set->has_instances()) {
+ return true;
+ }
+ const bool has_mesh = geometry_set->has_mesh();
+ const bool has_pointcloud = geometry_set->has_pointcloud();
+ const bool has_volume = geometry_set->has_volume();
+ const bool has_curve = geometry_set->has_curve();
+ if (ob->type == OB_MESH) {
+ return has_pointcloud || has_volume || has_curve;
+ }
+ if (ob->type == OB_POINTCLOUD) {
+ return has_mesh || has_volume || has_curve;
+ }
+ if (ob->type == OB_VOLUME) {
+ return has_mesh || has_pointcloud || has_curve;
+ }
+ if (ob->type == OB_CURVE) {
+ return has_mesh || has_pointcloud || has_volume;
+ }
+ return false;
}
/** \} */
diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc
index 32a65ab47bf..376792b9b96 100644
--- a/source/blender/blenkernel/intern/geometry_set_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_set_instances.cc
@@ -168,6 +168,11 @@ static void geometry_set_collect_recursive(const GeometrySet &geometry_set,
collection, instance_transform, r_sets);
break;
}
+ case InstanceReference::Type::GeometrySet: {
+ const GeometrySet &geometry_set = reference.geometry_set();
+ geometry_set_collect_recursive(geometry_set, instance_transform, r_sets);
+ break;
+ }
case InstanceReference::Type::None: {
break;
}
@@ -290,6 +295,13 @@ static bool instances_attribute_foreach_recursive(const GeometrySet &geometry_se
}
break;
}
+ case InstanceReference::Type::GeometrySet: {
+ const GeometrySet &geometry_set = reference.geometry_set();
+ if (!instances_attribute_foreach_recursive(geometry_set, callback, limit, count)) {
+ return false;
+ }
+ break;
+ }
case InstanceReference::Type::None: {
break;
}
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 062264c5729..bca1afbf101 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -1979,8 +1979,7 @@ int BKE_object_visibility(const Object *ob, const int dag_eval_mode)
visibility |= OB_VISIBLE_INSTANCES;
}
- if (ob->runtime.geometry_set_eval != NULL &&
- BKE_geometry_set_has_instances(ob->runtime.geometry_set_eval)) {
+ if (BKE_object_has_geometry_set_instances(ob)) {
visibility |= OB_VISIBLE_INSTANCES;
}
@@ -5737,3 +5736,13 @@ void BKE_object_modifiers_lib_link_common(void *userData,
id_us_plus_no_lib(*idpoin);
}
}
+
+void BKE_object_replace_data_on_shallow_copy(Object *ob, ID *new_data)
+{
+ ob->type = BKE_object_obdata_to_type(new_data);
+ ob->data = new_data;
+ ob->runtime.geometry_set_eval = NULL;
+ ob->runtime.data_eval = NULL;
+ ob->runtime.bb->flag |= BOUNDBOX_DIRTY;
+ ob->id.py_instance = NULL;
+}
diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc
index a46ac4b1175..47d4d03d1e1 100644
--- a/source/blender/blenkernel/intern/object_dupli.cc
+++ b/source/blender/blenkernel/intern/object_dupli.cc
@@ -194,6 +194,7 @@ static DupliObject *make_dupli(const DupliContext *ctx,
}
dob->ob = ob;
+ dob->ob_data = (ID *)ob->data;
mul_m4_m4m4(dob->mat, (float(*)[4])ctx->space_mat, mat);
dob->type = ctx->gen->type;
@@ -834,14 +835,59 @@ static const DupliGenerator gen_dupli_verts_pointcloud = {
/** \name Instances Geometry Component Implementation
* \{ */
-static void make_duplis_instances_component(const DupliContext *ctx)
+static void make_duplis_geometry_set_impl(const DupliContext *ctx,
+ const GeometrySet &geometry_set,
+ const float parent_transform[4][4],
+ bool geometry_set_is_instance)
{
- const InstancesComponent *component =
- ctx->object->runtime.geometry_set_eval->get_component_for_read<InstancesComponent>();
+ int component_index = 0;
+ if (ctx->object->type != OB_MESH || geometry_set_is_instance) {
+ const Mesh *mesh = geometry_set.get_mesh_for_read();
+ if (mesh != nullptr) {
+ DupliObject *dupli = make_dupli(ctx, ctx->object, parent_transform, component_index++);
+ dupli->ob_data = (ID *)mesh;
+ }
+ }
+ if (ctx->object->type != OB_VOLUME || geometry_set_is_instance) {
+ const Volume *volume = geometry_set.get_volume_for_read();
+ if (volume != nullptr) {
+ DupliObject *dupli = make_dupli(ctx, ctx->object, parent_transform, component_index++);
+ dupli->ob_data = (ID *)volume;
+ }
+ }
+ if (ctx->object->type != OB_CURVE || geometry_set_is_instance) {
+ const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>();
+ if (curve_component != nullptr) {
+ const Curve *curve = curve_component->get_curve_for_render();
+ if (curve != nullptr) {
+ DupliObject *dupli = make_dupli(ctx, ctx->object, parent_transform, component_index++);
+ dupli->ob_data = (ID *)curve;
+ }
+ }
+ }
+ if (ctx->object->type != OB_POINTCLOUD || geometry_set_is_instance) {
+ const PointCloud *pointcloud = geometry_set.get_pointcloud_for_read();
+ if (pointcloud != nullptr) {
+ DupliObject *dupli = make_dupli(ctx, ctx->object, parent_transform, component_index++);
+ dupli->ob_data = (ID *)pointcloud;
+ }
+ }
+ const bool creates_duplis_for_components = component_index >= 1;
+
+ const InstancesComponent *component = geometry_set.get_component_for_read<InstancesComponent>();
if (component == nullptr) {
return;
}
+ const DupliContext *instances_ctx = ctx;
+ /* 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. */
+ DupliContext new_instances_ctx;
+ if (creates_duplis_for_components) {
+ copy_dupli_context(&new_instances_ctx, ctx, ctx->object, nullptr, component_index);
+ instances_ctx = &new_instances_ctx;
+ }
+
Span<float4x4> instance_offset_matrices = component->instance_transforms();
Span<int> instance_reference_handles = component->instance_reference_handles();
Span<int> almost_unique_ids = component->almost_unique_ids();
@@ -855,13 +901,13 @@ static void make_duplis_instances_component(const DupliContext *ctx)
case InstanceReference::Type::Object: {
Object &object = reference.object();
float matrix[4][4];
- mul_m4_m4m4(matrix, ctx->object->obmat, instance_offset_matrices[i].values);
- make_dupli(ctx, &object, matrix, id);
+ mul_m4_m4m4(matrix, parent_transform, instance_offset_matrices[i].values);
+ make_dupli(instances_ctx, &object, matrix, id);
float space_matrix[4][4];
mul_m4_m4m4(space_matrix, instance_offset_matrices[i].values, object.imat);
- mul_m4_m4_pre(space_matrix, ctx->object->obmat);
- make_recursive_duplis(ctx, &object, space_matrix, id);
+ mul_m4_m4_pre(space_matrix, parent_transform);
+ make_recursive_duplis(instances_ctx, &object, space_matrix, id);
break;
}
case InstanceReference::Type::Collection: {
@@ -870,23 +916,36 @@ static void make_duplis_instances_component(const DupliContext *ctx)
unit_m4(collection_matrix);
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, ctx->object->obmat);
+ mul_m4_m4_pre(collection_matrix, parent_transform);
+
+ DupliContext sub_ctx;
+ copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id);
- eEvaluationMode mode = DEG_get_mode(ctx->depsgraph);
+ eEvaluationMode mode = DEG_get_mode(instances_ctx->depsgraph);
+ int object_id = 0;
FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (&collection, object, mode) {
- if (object == ctx->object) {
+ if (object == instances_ctx->object) {
continue;
}
float instance_matrix[4][4];
mul_m4_m4m4(instance_matrix, collection_matrix, object->obmat);
- make_dupli(ctx, object, instance_matrix, id);
- make_recursive_duplis(ctx, object, collection_matrix, id);
+ make_dupli(&sub_ctx, object, instance_matrix, object_id++);
+ make_recursive_duplis(&sub_ctx, object, collection_matrix, object_id++);
}
FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
break;
}
+ case InstanceReference::Type::GeometrySet: {
+ float new_transform[4][4];
+ mul_m4_m4m4(new_transform, parent_transform, instance_offset_matrices[i].values);
+
+ DupliContext sub_ctx;
+ 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);
+ break;
+ }
case InstanceReference::Type::None: {
break;
}
@@ -894,9 +953,15 @@ static void make_duplis_instances_component(const DupliContext *ctx)
}
}
-static const DupliGenerator gen_dupli_instances_component = {
+static void make_duplis_geometry_set(const DupliContext *ctx)
+{
+ const GeometrySet *geometry_set = ctx->object->runtime.geometry_set_eval;
+ make_duplis_geometry_set_impl(ctx, *geometry_set, ctx->object->obmat, false);
+}
+
+static const DupliGenerator gen_dupli_geometry_set = {
0,
- make_duplis_instances_component,
+ make_duplis_geometry_set,
};
/** \} */
@@ -1567,8 +1632,8 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
}
if (ctx->object->runtime.geometry_set_eval != nullptr) {
- if (BKE_geometry_set_has_instances(ctx->object->runtime.geometry_set_eval)) {
- return &gen_dupli_instances_component;
+ if (BKE_object_has_geometry_set_instances(ctx->object)) {
+ return &gen_dupli_geometry_set;
}
}
diff --git a/source/blender/blenlib/BLI_user_counter.hh b/source/blender/blenlib/BLI_user_counter.hh
index 3e6d5af4c3f..8cebadeac4c 100644
--- a/source/blender/blenlib/BLI_user_counter.hh
+++ b/source/blender/blenlib/BLI_user_counter.hh
@@ -84,12 +84,24 @@ template<typename T> class UserCounter {
return data_;
}
+ const T *operator->() const
+ {
+ BLI_assert(data_ != nullptr);
+ return data_;
+ }
+
T &operator*()
{
BLI_assert(data_ != nullptr);
return *data_;
}
+ const T &operator*() const
+ {
+ BLI_assert(data_ != nullptr);
+ return *data_;
+ }
+
operator bool() const
{
return data_ != nullptr;
diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h
index 17f5ca0db79..e9195a1eb26 100644
--- a/source/blender/depsgraph/DEG_depsgraph_query.h
+++ b/source/blender/depsgraph/DEG_depsgraph_query.h
@@ -145,15 +145,7 @@ typedef struct DEGObjectIterData {
eEvaluationMode eval_mode;
- /* **** Iteration over geometry components **** */
-
- /* The object whose components we currently iterate over.
- * This might point to #temp_dupli_object. */
- struct Object *geometry_component_owner;
- /* Some identifier that is used to determine which geometry component should be returned next. */
- int geometry_component_id;
- /* Temporary storage for an object that is created from a component. */
- struct Object temp_geometry_component_object;
+ struct Object *next_object;
/* **** Iteration over dupli-list. *** */
diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
index 770d9775dd3..7af3d03d478 100644
--- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
@@ -120,130 +120,6 @@ bool deg_object_hide_original(eEvaluationMode eval_mode, Object *ob, DupliObject
return false;
}
-void deg_iterator_components_init(DEGObjectIterData *data, Object *object)
-{
- data->geometry_component_owner = object;
- data->geometry_component_id = 0;
-}
-
-/* Returns false when iterator is exhausted. */
-bool deg_iterator_components_step(BLI_Iterator *iter)
-{
- DEGObjectIterData *data = (DEGObjectIterData *)iter->data;
- if (data->geometry_component_owner == nullptr) {
- return false;
- }
-
- if (data->geometry_component_owner->runtime.geometry_set_eval == nullptr) {
- /* Return the object itself, if it does not have a geometry set yet. */
- iter->current = data->geometry_component_owner;
- data->geometry_component_owner = nullptr;
- return true;
- }
-
- GeometrySet *geometry_set = data->geometry_component_owner->runtime.geometry_set_eval;
- if (geometry_set == nullptr) {
- data->geometry_component_owner = nullptr;
- return false;
- }
-
- /* The mesh component. */
- if (data->geometry_component_id == 0) {
- data->geometry_component_id++;
-
- /* Don't use a temporary object for this component, when the owner is a mesh object. */
- if (data->geometry_component_owner->type == OB_MESH) {
- iter->current = data->geometry_component_owner;
- return true;
- }
-
- const Mesh *mesh = geometry_set->get_mesh_for_read();
- if (mesh != nullptr) {
- Object *temp_object = &data->temp_geometry_component_object;
- *temp_object = *data->geometry_component_owner;
- temp_object->type = OB_MESH;
- temp_object->data = (void *)mesh;
- temp_object->runtime.select_id = data->geometry_component_owner->runtime.select_id;
- iter->current = temp_object;
- return true;
- }
- }
-
- /* The pointcloud component. */
- if (data->geometry_component_id == 1) {
- data->geometry_component_id++;
-
- /* Don't use a temporary object for this component, when the owner is a point cloud object. */
- if (data->geometry_component_owner->type == OB_POINTCLOUD) {
- iter->current = data->geometry_component_owner;
- return true;
- }
-
- const PointCloud *pointcloud = geometry_set->get_pointcloud_for_read();
- if (pointcloud != nullptr) {
- Object *temp_object = &data->temp_geometry_component_object;
- *temp_object = *data->geometry_component_owner;
- temp_object->type = OB_POINTCLOUD;
- temp_object->data = (void *)pointcloud;
- temp_object->runtime.select_id = data->geometry_component_owner->runtime.select_id;
- iter->current = temp_object;
- return true;
- }
- }
-
- /* The volume component. */
- if (data->geometry_component_id == 2) {
- data->geometry_component_id++;
-
- /* Don't use a temporary object for this component, when the owner is a volume object. */
- if (data->geometry_component_owner->type == OB_VOLUME) {
- iter->current = data->geometry_component_owner;
- return true;
- }
-
- const VolumeComponent *component = geometry_set->get_component_for_read<VolumeComponent>();
- if (component != nullptr) {
- const Volume *volume = component->get_for_read();
-
- if (volume != nullptr) {
- Object *temp_object = &data->temp_geometry_component_object;
- *temp_object = *data->geometry_component_owner;
- temp_object->type = OB_VOLUME;
- temp_object->data = (void *)volume;
- temp_object->runtime.select_id = data->geometry_component_owner->runtime.select_id;
- iter->current = temp_object;
- return true;
- }
- }
- }
-
- /* The curve component. */
- if (data->geometry_component_id == 3) {
- data->geometry_component_id++;
-
- const CurveComponent *component = geometry_set->get_component_for_read<CurveComponent>();
- if (component != nullptr) {
- const Curve *curve = component->get_curve_for_render();
-
- if (curve != nullptr) {
- Object *temp_object = &data->temp_geometry_component_object;
- *temp_object = *data->geometry_component_owner;
- temp_object->type = OB_CURVE;
- temp_object->data = (void *)curve;
- /* Assign data_eval here too, because curve rendering code tries
- * to use a mesh if it can find one in this pointer. */
- temp_object->runtime.data_eval = (ID *)curve;
- temp_object->runtime.select_id = data->geometry_component_owner->runtime.select_id;
- iter->current = temp_object;
- return true;
- }
- }
- }
-
- data->geometry_component_owner = nullptr;
- return false;
-}
-
void deg_iterator_duplis_init(DEGObjectIterData *data, Object *object)
{
if ((data->flag & DEG_ITER_OBJECT_FLAG_DUPLI) &&
@@ -292,6 +168,9 @@ bool deg_iterator_duplis_step(DEGObjectIterData *data)
temp_dupli_object->dt = MIN2(temp_dupli_object->dt, dupli_parent->dt);
copy_v4_v4(temp_dupli_object->color, dupli_parent->color);
temp_dupli_object->runtime.select_id = dupli_parent->runtime.select_id;
+ if (dob->ob->data != dob->ob_data) {
+ BKE_object_replace_data_on_shallow_copy(temp_dupli_object, dob->ob_data);
+ }
/* Duplicated elements shouldn't care whether their original collection is visible or not. */
temp_dupli_object->base_flag |= BASE_VISIBLE_DEPSGRAPH;
@@ -308,7 +187,7 @@ bool deg_iterator_duplis_step(DEGObjectIterData *data)
copy_m4_m4(data->temp_dupli_object.obmat, dob->mat);
invert_m4_m4(data->temp_dupli_object.imat, data->temp_dupli_object.obmat);
- deg_iterator_components_init(data, &data->temp_dupli_object);
+ data->next_object = &data->temp_dupli_object;
BLI_assert(deg::deg_validate_copy_on_write_datablock(&data->temp_dupli_object.id));
return true;
}
@@ -377,7 +256,7 @@ bool deg_iterator_objects_step(DEGObjectIterData *data)
}
if (ob_visibility & (OB_VISIBLE_SELF | OB_VISIBLE_PARTICLES)) {
- deg_iterator_components_init(data, object);
+ data->next_object = object;
}
data->id_node_index++;
return true;
@@ -400,6 +279,7 @@ void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGObjectIterData *data)
return;
}
+ data->next_object = nullptr;
data->dupli_parent = nullptr;
data->dupli_list = nullptr;
data->dupli_object_next = nullptr;
@@ -408,8 +288,6 @@ void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGObjectIterData *data)
data->id_node_index = 0;
data->num_id_nodes = num_id_nodes;
data->eval_mode = DEG_get_mode(depsgraph);
- data->geometry_component_id = 0;
- data->geometry_component_owner = nullptr;
deg_invalidate_iterator_work_data(data);
DEG_iterator_objects_next(iter);
@@ -419,7 +297,9 @@ void DEG_iterator_objects_next(BLI_Iterator *iter)
{
DEGObjectIterData *data = (DEGObjectIterData *)iter->data;
while (true) {
- if (deg_iterator_components_step(iter)) {
+ if (data->next_object != nullptr) {
+ iter->current = data->next_object;
+ data->next_object = nullptr;
return;
}
if (deg_iterator_duplis_step(data)) {
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 7f850435a64..9590a4aa7ee 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -632,14 +632,29 @@ void DRW_viewport_request_redraw(void)
/** \name Duplis
* \{ */
-static void drw_duplidata_load(DupliObject *dupli)
+static uint dupli_key_hash(const void *key)
{
+ const DupliKey *dupli_key = (const DupliKey *)key;
+ return BLI_ghashutil_ptrhash(dupli_key->ob) ^ BLI_ghashutil_ptrhash(dupli_key->ob_data);
+}
+
+static bool dupli_key_cmp(const void *key1, const void *key2)
+{
+ const DupliKey *dupli_key1 = (const DupliKey *)key1;
+ const DupliKey *dupli_key2 = (const DupliKey *)key2;
+ return dupli_key1->ob != dupli_key2->ob || dupli_key1->ob_data != dupli_key2->ob_data;
+}
+
+static void drw_duplidata_load(Object *ob)
+{
+ DupliObject *dupli = DST.dupli_source;
if (dupli == NULL) {
return;
}
- if (DST.dupli_origin != dupli->ob) {
+ if (DST.dupli_origin != dupli->ob || (DST.dupli_origin_data != dupli->ob_data)) {
DST.dupli_origin = dupli->ob;
+ DST.dupli_origin_data = dupli->ob_data;
}
else {
/* Same data as previous iter. No need to poll ghash for this. */
@@ -647,16 +662,23 @@ static void drw_duplidata_load(DupliObject *dupli)
}
if (DST.dupli_ghash == NULL) {
- DST.dupli_ghash = BLI_ghash_ptr_new(__func__);
+ DST.dupli_ghash = BLI_ghash_new(dupli_key_hash, dupli_key_cmp, __func__);
}
+ DupliKey *key = MEM_callocN(sizeof(DupliKey), __func__);
+ key->ob = dupli->ob;
+ key->ob_data = dupli->ob_data;
+
void **value;
- if (!BLI_ghash_ensure_p(DST.dupli_ghash, DST.dupli_origin, &value)) {
+ if (!BLI_ghash_ensure_p(DST.dupli_ghash, key, &value)) {
*value = MEM_callocN(sizeof(void *) * DST.enabled_engine_count, __func__);
/* TODO: Meh a bit out of place but this is nice as it is
- * only done once per "original" object. */
- drw_batch_cache_validate(DST.dupli_origin);
+ * only done once per instance type. */
+ drw_batch_cache_validate(ob);
+ }
+ else {
+ MEM_freeN(key);
}
DST.dupli_datas = *(void ***)value;
}
@@ -670,12 +692,24 @@ static void duplidata_value_free(void *val)
MEM_freeN(val);
}
+static void duplidata_key_free(void *key)
+{
+ DupliKey *dupli_key = (DupliKey *)key;
+ if (dupli_key->ob_data == NULL) {
+ drw_batch_cache_generate_requested(dupli_key->ob);
+ }
+ else {
+ Object temp_object = *dupli_key->ob;
+ BKE_object_replace_data_on_shallow_copy(&temp_object, dupli_key->ob_data);
+ drw_batch_cache_generate_requested(&temp_object);
+ }
+ MEM_freeN(key);
+}
+
static void drw_duplidata_free(void)
{
if (DST.dupli_ghash != NULL) {
- BLI_ghash_free(DST.dupli_ghash,
- (void (*)(void *key))drw_batch_cache_generate_requested,
- duplidata_value_free);
+ BLI_ghash_free(DST.dupli_ghash, duplidata_key_free, duplidata_value_free);
DST.dupli_ghash = NULL;
}
}
@@ -1523,6 +1557,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
/* Only iterate over objects for internal engines or when overlays are enabled */
if (do_populate_loop) {
DST.dupli_origin = NULL;
+ DST.dupli_origin_data = NULL;
DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (depsgraph, ob) {
if ((object_type_exclude_viewport & (1 << ob->type)) != 0) {
continue;
@@ -1532,7 +1567,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
}
DST.dupli_parent = data_.dupli_parent;
DST.dupli_source = data_.dupli_object_current;
- drw_duplidata_load(DST.dupli_source);
+ drw_duplidata_load(ob);
drw_engines_cache_populate(ob);
}
DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END;
@@ -1881,12 +1916,13 @@ void DRW_render_object_iter(
draw_ctx->v3d->object_type_exclude_viewport :
0;
DST.dupli_origin = NULL;
+ DST.dupli_origin_data = NULL;
DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (depsgraph, ob) {
if ((object_type_exclude_viewport & (1 << ob->type)) == 0) {
DST.dupli_parent = data_.dupli_parent;
DST.dupli_source = data_.dupli_object_current;
DST.ob_handle = 0;
- drw_duplidata_load(DST.dupli_source);
+ drw_duplidata_load(ob);
if (!DST.dupli_source) {
drw_batch_cache_validate(ob);
@@ -2330,6 +2366,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
v3d->object_type_exclude_select);
bool filter_exclude = false;
DST.dupli_origin = NULL;
+ DST.dupli_origin_data = NULL;
DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (depsgraph, ob) {
if (!BKE_object_is_visible_in_viewport(v3d, ob)) {
continue;
@@ -2362,7 +2399,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
DRW_select_load_id(ob->runtime.select_id);
DST.dupli_parent = data_.dupli_parent;
DST.dupli_source = data_.dupli_object_current;
- drw_duplidata_load(DST.dupli_source);
+ drw_duplidata_load(ob);
drw_engines_cache_populate(ob);
}
}
@@ -2475,6 +2512,7 @@ static void drw_draw_depth_loop_impl(struct Depsgraph *depsgraph,
const int object_type_exclude_viewport = v3d->object_type_exclude_viewport;
DST.dupli_origin = NULL;
+ DST.dupli_origin_data = NULL;
DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (DST.draw_ctx.depsgraph, ob) {
if ((object_type_exclude_viewport & (1 << ob->type)) != 0) {
continue;
@@ -2484,7 +2522,7 @@ static void drw_draw_depth_loop_impl(struct Depsgraph *depsgraph,
}
DST.dupli_parent = data_.dupli_parent;
DST.dupli_source = data_.dupli_object_current;
- drw_duplidata_load(DST.dupli_source);
+ drw_duplidata_load(ob);
drw_engines_cache_populate(ob);
}
DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END;
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index 33e1a57198c..1747ca752c7 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -497,6 +497,11 @@ typedef struct DRWDebugSphere {
/* ------------- DRAW MANAGER ------------ */
+typedef struct DupliKey {
+ struct Object *ob;
+ struct ID *ob_data;
+} DupliKey;
+
#define DST_MAX_SLOTS 64 /* Cannot be changed without modifying RST.bound_tex_slots */
#define MAX_CLIP_PLANES 6 /* GL_MAX_CLIP_PLANES is at least 6 */
#define STENCIL_UNDEFINED 256
@@ -515,15 +520,19 @@ typedef struct DRWManager {
/** Handle of next DRWPass to be allocated. */
DRWResourceHandle pass_handle;
- /** Dupli state. NULL if not dupli. */
+ /** Dupli object that corresponds to the current object. */
struct DupliObject *dupli_source;
+ /** Object that created the dupli-list the current object is part of. */
struct Object *dupli_parent;
+ /** Object referenced by the current dupli object. */
struct Object *dupli_origin;
- /** Ghash containing original objects. */
+ /** Object-data referenced by the current dupli object. */
+ struct ID *dupli_origin_data;
+ /** Ghash: #DupliKey -> void pointer for each enabled engine. */
struct GHash *dupli_ghash;
/** TODO(fclem): try to remove usage of this. */
DRWInstanceData *object_instance_data[MAX_INSTANCE_DATA_SIZE];
- /* Array of dupli_data (one for each enabled engine) to handle duplis. */
+ /* Dupli data for the current dupli for each enabled engine. */
void **dupli_datas;
/* Rendering state */
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 2e34284f46e..f95e3f3b236 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -2246,13 +2246,6 @@ static bool dupliobject_instancer_cmp(const void *a_, const void *b_)
return false;
}
-static bool object_has_geometry_set_instances(const Object *object_eval)
-{
- struct GeometrySet *geometry_set = object_eval->runtime.geometry_set_eval;
-
- return (geometry_set != NULL) && BKE_geometry_set_has_instances(geometry_set);
-}
-
static void make_object_duplilist_real(bContext *C,
Depsgraph *depsgraph,
Scene *scene,
@@ -2266,7 +2259,8 @@ static void make_object_duplilist_real(bContext *C,
Object *object_eval = DEG_get_evaluated_object(depsgraph, base->object);
- if (!(base->object->transflag & OB_DUPLI) && !object_has_geometry_set_instances(object_eval)) {
+ if (!(base->object->transflag & OB_DUPLI) &&
+ !BKE_object_has_geometry_set_instances(object_eval)) {
return;
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh b/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh
index 680da9b6794..97170693cb3 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh
@@ -35,6 +35,10 @@ struct CollectionCellValue {
const Collection *collection;
};
+struct GeometrySetCellValue {
+ const GeometrySet *geometry_set;
+};
+
/**
* This is a type that can hold the value of a cell in a spreadsheet. This type allows us to
* decouple the drawing of individual cells from the code that generates the data to be displayed.
@@ -53,6 +57,7 @@ class CellValue {
std::optional<ColorGeometry4f> value_color;
std::optional<ObjectCellValue> value_object;
std::optional<CollectionCellValue> value_collection;
+ std::optional<GeometrySetCellValue> value_geometry_set;
};
} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
index e38c70afd0f..12815c2c7e9 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
@@ -332,6 +332,11 @@ std::unique_ptr<ColumnValues> InstancesDataSource::get_column_values(
r_cell_value.value_collection = CollectionCellValue{&collection};
break;
}
+ case InstanceReference::Type::GeometrySet: {
+ const GeometrySet &geometry_set = reference.geometry_set();
+ r_cell_value.value_geometry_set = GeometrySetCellValue{&geometry_set};
+ break;
+ }
case InstanceReference::Type::None: {
break;
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
index 8079763a339..1a5eac53306 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
@@ -209,6 +209,23 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
0,
nullptr);
}
+ else if (cell_value.value_geometry_set.has_value()) {
+ uiDefIconTextBut(params.block,
+ UI_BTYPE_LABEL,
+ 0,
+ ICON_MESH_DATA,
+ "Geometry",
+ params.xmin,
+ params.ymin,
+ params.width,
+ params.height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+ }
}
void draw_float_vector(const CellDrawParams &params, const Span<float> values) const
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index bb04f557074..811f30c96e5 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -501,9 +501,7 @@ static void iter_snap_objects(SnapObjectContext *sctx,
}
Object *obj_eval = DEG_get_evaluated_object(depsgraph, base->object);
- if (obj_eval->transflag & OB_DUPLI ||
- (obj_eval->runtime.geometry_set_eval != NULL &&
- BKE_geometry_set_has_instances(obj_eval->runtime.geometry_set_eval))) {
+ if (obj_eval->transflag & OB_DUPLI || BKE_object_has_geometry_set_instances(obj_eval)) {
ListBase *lb = object_duplilist(depsgraph, sctx->scene, obj_eval);
for (DupliObject *dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
BLI_assert(DEG_is_evaluated_object(dupli_ob->ob));
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 43dd4b4270e..fd67150811d 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -1889,6 +1889,7 @@ typedef enum GeometryNodeTriangulateQuads {
typedef enum GeometryNodePointInstanceType {
GEO_NODE_POINT_INSTANCE_TYPE_OBJECT = 0,
GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION = 1,
+ GEO_NODE_POINT_INSTANCE_TYPE_GEOMETRY = 2,
} GeometryNodePointInstanceType;
typedef enum GeometryNodePointInstanceFlag {
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 9e24a36915e..a7c0372f309 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -9295,6 +9295,11 @@ static void def_geo_point_instance(StructRNA *srna)
ICON_NONE,
"Collection",
"Instance an entire collection on all points"},
+ {GEO_NODE_POINT_INSTANCE_TYPE_GEOMETRY,
+ "GEOMETRY",
+ ICON_NONE,
+ "Geometry",
+ "Copy geometry to all points"},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
index 36017307739..9f67638de7e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
@@ -31,13 +31,14 @@ static void geo_node_point_instance_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Object>("Object").hide_label(true);
b.add_input<decl::Collection>("Collection").hide_label(true);
+ b.add_input<decl::Geometry>("Instance Geometry");
b.add_input<decl::Int>("Seed").min(-10000).max(10000);
b.add_output<decl::Geometry>("Geometry");
}
static void geo_node_point_instance_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "instance_type", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "instance_type", 0, nullptr, ICON_NONE);
if (RNA_enum_get(ptr, "instance_type") == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION) {
uiItemR(layout, ptr, "use_whole_collection", 0, nullptr, ICON_NONE);
}
@@ -56,7 +57,8 @@ static void geo_node_point_instance_update(bNodeTree *UNUSED(tree), bNode *node)
{
bNodeSocket *object_socket = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
bNodeSocket *collection_socket = object_socket->next;
- bNodeSocket *seed_socket = collection_socket->next;
+ bNodeSocket *instance_geometry_socket = collection_socket->next;
+ bNodeSocket *seed_socket = instance_geometry_socket->next;
NodeGeometryPointInstance *node_storage = (NodeGeometryPointInstance *)node->storage;
GeometryNodePointInstanceType type = (GeometryNodePointInstanceType)node_storage->instance_type;
@@ -65,6 +67,8 @@ static void geo_node_point_instance_update(bNodeTree *UNUSED(tree), bNode *node)
nodeSetSocketAvailability(object_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_OBJECT);
nodeSetSocketAvailability(collection_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION);
+ nodeSetSocketAvailability(instance_geometry_socket,
+ type == GEO_NODE_POINT_INSTANCE_TYPE_GEOMETRY);
nodeSetSocketAvailability(
seed_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION && !use_whole_collection);
}
@@ -114,6 +118,12 @@ static Vector<InstanceReference> get_instance_references__collection(GeoNodeExec
return references;
}
+static Vector<InstanceReference> get_instance_references__geometry(GeoNodeExecParams &params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Instance Geometry");
+ return {std::move(geometry_set)};
+}
+
static Vector<InstanceReference> get_instance_references(GeoNodeExecParams &params)
{
const bNode &node = params.node();
@@ -128,6 +138,9 @@ static Vector<InstanceReference> get_instance_references(GeoNodeExecParams &para
case GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION: {
return get_instance_references__collection(params);
}
+ case GEO_NODE_POINT_INSTANCE_TYPE_GEOMETRY: {
+ return get_instance_references__geometry(params);
+ }
}
return {};
}